Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06fdc75945 | ||
|
|
ded971a3ec | ||
|
|
abc0f99ddd | ||
|
|
b3a88d6ea7 | ||
|
|
76014b7cb9 | ||
|
|
0ab6eb6587 | ||
|
|
a4e99366fb | ||
|
|
a32ab4cc97 | ||
|
|
e7f3c42f9d | ||
|
|
d76a0d7416 | ||
|
|
79f4af8ab5 | ||
|
|
a5f83329cb | ||
|
|
267479f31d | ||
|
|
164462e510 | ||
|
|
6331df306f | ||
|
|
027ceebcbd | ||
|
|
edb2c0080c | ||
|
|
caafc87b29 | ||
|
|
5d37cac4a0 | ||
|
|
8f68e096d4 | ||
|
|
430cad48e3 | ||
|
|
757a9532e6 | ||
|
|
f26f8cafa9 | ||
|
|
128a79e355 | ||
|
|
cc2d99db3a | ||
|
|
30a31d931a | ||
|
|
1c30d449bf | ||
|
|
dc4ce58248 | ||
|
|
dc93e861c7 | ||
|
|
960daf27e2 | ||
|
|
844f21344d | ||
|
|
535ad110e3 | ||
|
|
0e0d7a5441 | ||
|
|
ed63221c7e | ||
|
|
f9c2d7767d | ||
|
|
cb91478590 | ||
|
|
5dec7fe27d | ||
|
|
575d487c65 | ||
|
|
2b9289f402 | ||
|
|
9273683d3c | ||
|
|
88f8465e7e | ||
|
|
f26031cada | ||
|
|
3352d71515 | ||
|
|
999f9532ee | ||
|
|
d1f62ca9bf | ||
|
|
ef9f0cf635 | ||
|
|
d745564451 | ||
|
|
d37ac992fc | ||
|
|
e7fc3de90c | ||
|
|
bde81380c3 | ||
|
|
839b482cb5 | ||
|
|
72f70d4789 | ||
|
|
d646bbf5c1 | ||
|
|
e68aaf6540 | ||
|
|
20ab5ed0fa | ||
|
|
8590e390a2 | ||
|
|
ab1d558420 | ||
|
|
53c9021455 |
@@ -32,11 +32,11 @@ on:
|
||||
qt_binary_url:
|
||||
required: false
|
||||
type: string
|
||||
default: https://github.com/PCSX2/pcsx2-windows-dependencies/releases/download/2022-11-20/qt-6.4.0-x64.7z
|
||||
default: https://github.com/PCSX2/pcsx2-windows-dependencies/releases/download/2023-04-25/qt-6.5.0-x64.7z
|
||||
qt_dir:
|
||||
required: false
|
||||
type: string
|
||||
default: 3rdparty\qt\6.4.0\msvc2022_64
|
||||
default: 3rdparty\qt\6.5.0\msvc2022_64
|
||||
cheats_url:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
@@ -537,6 +537,7 @@
|
||||
030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
|
||||
030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
|
||||
030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,
|
||||
030000009b2800006300000000000000,Raphnet N64 Adapter,a:b0,b:b1,start:b3,lefttrigger:b2,dpup:b10,dpleft:b12,dpdown:b11,dpright:b13,leftx:a0,lefty:a1,-rightx:b8,+rightx:b9,-righty:b6,+righty:b7,leftshoulder:b4,rightshoulder:b5,platform:Windows,
|
||||
030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,
|
||||
030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows,
|
||||
030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
@@ -663,6 +664,7 @@
|
||||
03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,
|
||||
03000000790000002601000000000000,TGZ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,platform:Windows,
|
||||
030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
|
||||
030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000004f0400000ed0000000000000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -983,6 +985,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X,
|
||||
030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,
|
||||
030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,
|
||||
@@ -1332,7 +1335,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
|
||||
030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
|
||||
050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux,
|
||||
050000007e0500001920000001800000,NSO N64 Controller,a:b0,b:b1,guide:b11,misc1:b12,start:b6,leftshoulder:b3,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,-rightx:b9,+rightx:b10,-righty:b7,+righty:b8,lefttrigger:b2,righttrigger:b5,platform:Linux,
|
||||
050000007e0500001920000001800000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux,
|
||||
050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
|
||||
03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
|
||||
|
||||
@@ -128,11 +128,12 @@ ProcessedVertex load_vertex(uint index)
|
||||
#endif
|
||||
|
||||
vec2 i_st = rvtx.ST;
|
||||
vec4 i_c = vec4(uvec4(rvtx.RGBA & 0xFFu, (rvtx.RGBA >> 8) & 0xFFu, (rvtx.RGBA >> 16) & 0xFFu, rvtx.RGBA >> 24));
|
||||
vec4 i_c = vec4(uvec4(bitfieldExtract(rvtx.RGBA, 0, 8), bitfieldExtract(rvtx.RGBA, 8, 8),
|
||||
bitfieldExtract(rvtx.RGBA, 16, 8), bitfieldExtract(rvtx.RGBA, 24, 8)));
|
||||
float i_q = rvtx.Q;
|
||||
uvec2 i_p = uvec2(rvtx.XY & 0xFFFFu, rvtx.XY >> 16);
|
||||
uvec2 i_p = uvec2(bitfieldExtract(rvtx.XY, 0, 16), bitfieldExtract(rvtx.XY, 16, 16));
|
||||
uint i_z = rvtx.Z;
|
||||
uvec2 i_uv = uvec2(rvtx.UV & 0xFFFFu, rvtx.UV >> 16);
|
||||
uvec2 i_uv = uvec2(bitfieldExtract(rvtx.UV, 0, 16), bitfieldExtract(rvtx.UV, 16, 16));
|
||||
vec4 i_f = unpackUnorm4x8(rvtx.FOG);
|
||||
|
||||
ProcessedVertex vtx;
|
||||
|
||||
@@ -113,11 +113,12 @@ ProcessedVertex load_vertex(uint index)
|
||||
RawVertex rvtx = vertex_buffer[gl_BaseVertexARB + index];
|
||||
|
||||
vec2 a_st = rvtx.ST;
|
||||
uvec4 a_c = uvec4(rvtx.RGBA & 0xFFu, (rvtx.RGBA >> 8) & 0xFFu, (rvtx.RGBA >> 16) & 0xFFu, rvtx.RGBA >> 24);
|
||||
uvec4 a_c = uvec4(bitfieldExtract(rvtx.RGBA, 0, 8), bitfieldExtract(rvtx.RGBA, 8, 8),
|
||||
bitfieldExtract(rvtx.RGBA, 16, 8), bitfieldExtract(rvtx.RGBA, 24, 8));
|
||||
float a_q = rvtx.Q;
|
||||
uvec2 a_p = uvec2(rvtx.XY & 0xFFFFu, rvtx.XY >> 16);
|
||||
uvec2 a_p = uvec2(bitfieldExtract(rvtx.XY, 0, 16), bitfieldExtract(rvtx.XY, 16, 16));
|
||||
uint a_z = rvtx.Z;
|
||||
uvec2 a_uv = uvec2(rvtx.UV & 0xFFFFu, rvtx.UV >> 16);
|
||||
uvec2 a_uv = uvec2(bitfieldExtract(rvtx.UV, 0, 16), bitfieldExtract(rvtx.UV, 16, 16));
|
||||
vec4 a_f = unpackUnorm4x8(rvtx.FOG);
|
||||
|
||||
ProcessedVertex vtx;
|
||||
|
||||
@@ -52,9 +52,6 @@ if(MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
set(USE_CLANG TRUE)
|
||||
message(STATUS "Building with Clang/LLVM.")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
set(USE_ICC TRUE)
|
||||
message(STATUS "Building with Intel's ICC.")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(USE_GCC TRUE)
|
||||
message(STATUS "Building with GNU GCC")
|
||||
@@ -106,21 +103,13 @@ include(TargetArch)
|
||||
target_architecture(PCSX2_TARGET_ARCHITECTURES)
|
||||
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
message(STATUS "Compiling a ${PCSX2_TARGET_ARCHITECTURES} build on a ${CMAKE_HOST_SYSTEM_PROCESSOR} host.")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported architecture: ${PCSX2_TARGET_ARCHITECTURES}")
|
||||
endif()
|
||||
|
||||
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
# x86_64 requires -fPIC
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if(NOT DEFINED ARCH_FLAG AND NOT MSVC)
|
||||
if (DISABLE_ADVANCE_SIMD)
|
||||
if (USE_ICC)
|
||||
set(ARCH_FLAG "-msse2 -msse4.1")
|
||||
else()
|
||||
set(ARCH_FLAG "-msse -msse2 -msse4.1 -mfxsr")
|
||||
endif()
|
||||
set(ARCH_FLAG "-msse -msse2 -msse4.1 -mfxsr")
|
||||
else()
|
||||
#set(ARCH_FLAG "-march=native -fabi-version=6")
|
||||
set(ARCH_FLAG "-march=native")
|
||||
@@ -132,9 +121,6 @@ if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
set(_ARCH_64 1)
|
||||
set(_M_X86 1)
|
||||
else()
|
||||
# All but i386 requires -fPIC
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
message(FATAL_ERROR "Unsupported architecture: ${PCSX2_TARGET_ARCHITECTURES}")
|
||||
endif()
|
||||
string(REPLACE " " ";" ARCH_FLAG_LIST "${ARCH_FLAG}")
|
||||
@@ -220,24 +206,13 @@ endif()
|
||||
if (MSVC)
|
||||
set(DEFAULT_WARNINGS)
|
||||
else()
|
||||
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-attributes -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers -Wno-format -Wno-format-security)
|
||||
if (NOT USE_ICC)
|
||||
list(APPEND DEFAULT_WARNINGS -Wno-unused-value)
|
||||
endif()
|
||||
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-attributes -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers -Wno-format -Wno-format-security -Wno-unused-value)
|
||||
endif()
|
||||
|
||||
if (USE_GCC)
|
||||
list(APPEND DEFAULT_WARNINGS -Wno-stringop-truncation -Wno-stringop-overflow -Wno-maybe-uninitialized )
|
||||
endif()
|
||||
|
||||
|
||||
# -Wstrict-aliasing=n: to fix one day aliasing issue. n=1/2/3
|
||||
if (USE_ICC)
|
||||
set(AGGRESSIVE_WARNING -Wstrict-aliasing)
|
||||
elseif(NOT MSVC)
|
||||
set(AGGRESSIVE_WARNING -Wstrict-aliasing -Wstrict-overflow=1)
|
||||
endif()
|
||||
|
||||
if (USE_PGO_GENERATE OR USE_PGO_OPTIMIZE)
|
||||
add_compile_options("-fprofile-dir=${CMAKE_SOURCE_DIR}/profile")
|
||||
endif()
|
||||
@@ -264,7 +239,7 @@ if(USE_CLANG AND TIMETRACE)
|
||||
add_compile_options(-ftime-trace)
|
||||
endif()
|
||||
|
||||
set(PCSX2_WARNINGS ${DEFAULT_WARNINGS} ${AGGRESSIVE_WARNING})
|
||||
set(PCSX2_WARNINGS ${DEFAULT_WARNINGS})
|
||||
|
||||
if(DISABLE_BUILD_DATE)
|
||||
message(STATUS "Disabling the inclusion of the binary compile date.")
|
||||
|
||||
@@ -134,7 +134,7 @@ find_optional_system_library(libzip 3rdparty/libzip 1.8.0)
|
||||
if(QT_BUILD)
|
||||
# Default to bundled Qt6 for Windows.
|
||||
if(WIN32 AND NOT DEFINED Qt6_DIR)
|
||||
set(Qt6_DIR ${CMAKE_SOURCE_DIR}/3rdparty/qt/6.4.0/msvc2022_64/lib/cmake/Qt6)
|
||||
set(Qt6_DIR ${CMAKE_SOURCE_DIR}/3rdparty/qt/6.5.0/msvc2022_64/lib/cmake/Qt6)
|
||||
endif()
|
||||
|
||||
# Find the Qt components that we need.
|
||||
|
||||
@@ -468,10 +468,11 @@ namespace Vulkan
|
||||
SupportsExtension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_line_rasterization =
|
||||
SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access =
|
||||
SupportsExtension(VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, false) ||
|
||||
SupportsExtension(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_driver_properties =
|
||||
SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_arm_rasterization_order_attachment_access =
|
||||
SupportsExtension(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_fragment_shader_barycentric =
|
||||
SupportsExtension(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_shader_draw_parameters =
|
||||
@@ -490,7 +491,6 @@ namespace Vulkan
|
||||
|
||||
// Enable the features we use.
|
||||
m_device_features.dualSrcBlend = available_features.dualSrcBlend;
|
||||
m_device_features.geometryShader = available_features.geometryShader;
|
||||
m_device_features.largePoints = available_features.largePoints;
|
||||
m_device_features.wideLines = available_features.wideLines;
|
||||
m_device_features.fragmentStoresAndAtomics = available_features.fragmentStoresAndAtomics;
|
||||
@@ -664,8 +664,8 @@ namespace Vulkan
|
||||
// provoking vertex
|
||||
VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT};
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
|
||||
@@ -679,7 +679,7 @@ namespace Vulkan
|
||||
line_rasterization_feature.bresenhamLines = VK_TRUE;
|
||||
Util::AddPointerToChain(&device_info, &line_rasterization_feature);
|
||||
}
|
||||
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
|
||||
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
||||
{
|
||||
rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess = VK_TRUE;
|
||||
Util::AddPointerToChain(&device_info, &rasterization_order_access_feature);
|
||||
@@ -745,15 +745,15 @@ namespace Vulkan
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT};
|
||||
|
||||
// add in optional feature structs
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
Util::AddPointerToChain(&features2, &provoking_vertex_features);
|
||||
if (m_optional_extensions.vk_ext_line_rasterization)
|
||||
Util::AddPointerToChain(&features2, &line_rasterization_feature);
|
||||
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
|
||||
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
||||
Util::AddPointerToChain(&features2, &rasterization_order_access_feature);
|
||||
|
||||
// query
|
||||
@@ -761,7 +761,7 @@ namespace Vulkan
|
||||
|
||||
// confirm we actually support it
|
||||
m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE);
|
||||
m_optional_extensions.vk_arm_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_line_rasterization &= (line_rasterization_feature.bresenhamLines == VK_TRUE);
|
||||
|
||||
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
@@ -817,8 +817,8 @@ namespace Vulkan
|
||||
m_optional_extensions.vk_ext_line_rasterization ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_calibrated_timestamps is %s",
|
||||
m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_ARM_rasterization_order_attachment_access is %s",
|
||||
m_optional_extensions.vk_arm_rasterization_order_attachment_access ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_rasterization_order_attachment_access is %s",
|
||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported");
|
||||
}
|
||||
|
||||
bool Context::CreateAllocator()
|
||||
@@ -1666,7 +1666,7 @@ namespace Vulkan
|
||||
input_reference.layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
input_reference_ptr = &input_reference;
|
||||
|
||||
if (!g_vulkan_context->GetOptionalExtensions().vk_arm_rasterization_order_attachment_access)
|
||||
if (!g_vulkan_context->GetOptionalExtensions().vk_ext_rasterization_order_attachment_access)
|
||||
{
|
||||
// don't need the framebuffer-local dependency when we have rasterization order attachment access
|
||||
subpass_dependency.srcSubpass = 0;
|
||||
@@ -1699,7 +1699,9 @@ namespace Vulkan
|
||||
}
|
||||
|
||||
const VkSubpassDescriptionFlags subpass_flags =
|
||||
(key.color_feedback_loop && g_vulkan_context->GetOptionalExtensions().vk_arm_rasterization_order_attachment_access) ? VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM : 0;
|
||||
(key.color_feedback_loop && g_vulkan_context->GetOptionalExtensions().vk_ext_rasterization_order_attachment_access) ?
|
||||
VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT :
|
||||
0;
|
||||
const VkSubpassDescription subpass = {subpass_flags, VK_PIPELINE_BIND_POINT_GRAPHICS, input_reference_ptr ? 1u : 0u,
|
||||
input_reference_ptr ? input_reference_ptr : nullptr, color_reference_ptr ? 1u : 0u,
|
||||
color_reference_ptr ? color_reference_ptr : nullptr, nullptr, depth_reference_ptr, 0, nullptr};
|
||||
|
||||
@@ -53,8 +53,8 @@ namespace Vulkan
|
||||
bool vk_ext_memory_budget : 1;
|
||||
bool vk_ext_calibrated_timestamps : 1;
|
||||
bool vk_ext_line_rasterization : 1;
|
||||
bool vk_ext_rasterization_order_attachment_access : 1;
|
||||
bool vk_khr_driver_properties : 1;
|
||||
bool vk_arm_rasterization_order_attachment_access : 1;
|
||||
bool vk_khr_fragment_shader_barycentric : 1;
|
||||
bool vk_khr_shader_draw_parameters : 1;
|
||||
};
|
||||
|
||||
@@ -545,9 +545,7 @@ namespace Vulkan
|
||||
// Determine the dimensions of the swap chain. Values of -1 indicate the size we specify here
|
||||
// determines window size?
|
||||
VkExtent2D size = surface_capabilities.currentExtent;
|
||||
#ifndef ANDROID
|
||||
if (size.width == UINT32_MAX)
|
||||
#endif
|
||||
{
|
||||
size.width = m_window_info.surface_width;
|
||||
size.height = m_window_info.surface_height;
|
||||
@@ -562,6 +560,14 @@ namespace Vulkan
|
||||
if (!(surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR))
|
||||
transform = surface_capabilities.currentTransform;
|
||||
|
||||
VkCompositeAlphaFlagBitsKHR alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
if (!(surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
|
||||
{
|
||||
// If we only support pre-multiplied/post-multiplied... :/
|
||||
if (surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
|
||||
alpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
|
||||
}
|
||||
|
||||
// Select swap chain flags, we only need a colour attachment
|
||||
VkImageUsageFlags image_usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
if (!(surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT))
|
||||
@@ -577,7 +583,7 @@ namespace Vulkan
|
||||
// Now we can actually create the swap chain
|
||||
VkSwapchainCreateInfoKHR swap_chain_info = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, nullptr, 0, m_surface,
|
||||
image_count, m_surface_format.format, m_surface_format.colorSpace, size, 1u, image_usage,
|
||||
VK_SHARING_MODE_EXCLUSIVE, 0, nullptr, transform, VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, m_present_mode,
|
||||
VK_SHARING_MODE_EXCLUSIVE, 0, nullptr, transform, alpha, m_present_mode,
|
||||
VK_TRUE, old_swap_chain};
|
||||
std::array<uint32_t, 2> indices = {{
|
||||
g_vulkan_context->GetGraphicsQueueFamilyIndex(),
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<BinaryOutputDir>$(SolutionDir)bin\</BinaryOutputDir>
|
||||
<PCSX2QTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)3rdparty\qt\6.4.0\msvc2022_64\</PCSX2QTDIRDefault>
|
||||
<PCSX2QTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)3rdparty\qt\6.4.0\msvc2022_arm64\</PCSX2QTDIRDefault>
|
||||
<PCSX2QTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)3rdparty\qt\6.5.0\msvc2022_64\</PCSX2QTDIRDefault>
|
||||
<PCSX2QTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)3rdparty\qt\6.5.0\msvc2022_arm64\</PCSX2QTDIRDefault>
|
||||
<PCSX2QTDIR Condition="Exists('$(PCSX2QTDIRDefault)') And ('$(PCSX2QTDIR)'=='' Or !Exists('$(PCSX2QTDIR)'))">$(PCSX2QTDIRDefault)</PCSX2QTDIR>
|
||||
<PCSX2QTDIR Condition="Exists('$(PCSX2QTDIR)') And !HasTrailingSlash('$(PCSX2QTDIR)')">$(PCSX2QTDIR)\</PCSX2QTDIR>
|
||||
<PCSX2QTDIRHost>$(SolutionDir)3rdparty\qt\6.4.0\msvc2022_64\</PCSX2QTDIRHost>
|
||||
<PCSX2QTDIRHost>$(SolutionDir)3rdparty\qt\6.5.0\msvc2022_64\</PCSX2QTDIRHost>
|
||||
<QtDirValid>false</QtDirValid>
|
||||
<QtDirValid Condition="Exists('$(PCSX2QTDIR)')">true</QtDirValid>
|
||||
<QtIncludeDir>$(PCSX2QTDIR)include\</QtIncludeDir>
|
||||
|
||||
@@ -24,6 +24,8 @@ target_sources(pcsx2-qt PRIVATE
|
||||
MainWindow.ui
|
||||
PrecompiledHeader.cpp
|
||||
PrecompiledHeader.h
|
||||
SettingWidgetBinder.h
|
||||
Themes.cpp
|
||||
QtHost.cpp
|
||||
QtHost.h
|
||||
QtKeyCodes.cpp
|
||||
@@ -31,7 +33,6 @@ target_sources(pcsx2-qt PRIVATE
|
||||
QtProgressCallback.h
|
||||
QtUtils.cpp
|
||||
QtUtils.h
|
||||
SettingWidgetBinder.h
|
||||
GameList/EmptyGameListWidget.ui
|
||||
GameList/GameListModel.cpp
|
||||
GameList/GameListModel.h
|
||||
|
||||
@@ -181,7 +181,7 @@ void GameListWidget::initialize()
|
||||
m_list_view = new GameListGridListView(m_ui.stack);
|
||||
m_list_view->setModel(m_sort_model);
|
||||
m_list_view->setModelColumn(GameListModel::Column_Cover);
|
||||
m_list_view->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
m_list_view->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_list_view->setViewMode(QListView::IconMode);
|
||||
m_list_view->setResizeMode(QListView::Adjust);
|
||||
m_list_view->setUniformItemSizes(true);
|
||||
|
||||
@@ -66,7 +66,6 @@
|
||||
#include "pcsx2/Frontend/Achievements.h"
|
||||
#endif
|
||||
|
||||
|
||||
const char* MainWindow::OPEN_FILE_FILTER =
|
||||
QT_TRANSLATE_NOOP("MainWindow", "All File Types (*.bin *.iso *.cue *.chd *.cso *.gz *.elf *.irx *.gs *.gs.xz *.gs.zst *.dump);;"
|
||||
"Single-Track Raw Images (*.bin *.iso);;"
|
||||
@@ -87,16 +86,7 @@ const char* MainWindow::DISC_IMAGE_FILTER = QT_TRANSLATE_NOOP("MainWindow", "All
|
||||
"GZ Images (*.gz);;"
|
||||
"Block Dumps (*.dump)");
|
||||
|
||||
#ifdef __APPLE__
|
||||
const char* MainWindow::DEFAULT_THEME_NAME = "";
|
||||
#else
|
||||
const char* MainWindow::DEFAULT_THEME_NAME = "darkfusion";
|
||||
#endif
|
||||
|
||||
MainWindow* g_main_window = nullptr;
|
||||
static QString s_unthemed_style_name;
|
||||
static QPalette s_unthemed_palette;
|
||||
static bool s_unthemed_style_name_set;
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
static const bool s_use_central_widget = false;
|
||||
@@ -503,453 +493,7 @@ void MainWindow::resetSettings(bool ui)
|
||||
g_main_window->recreateSettings();
|
||||
}
|
||||
|
||||
void MainWindow::updateApplicationTheme()
|
||||
{
|
||||
if (!s_unthemed_style_name_set)
|
||||
{
|
||||
s_unthemed_style_name_set = true;
|
||||
s_unthemed_style_name = QApplication::style()->objectName();
|
||||
s_unthemed_palette = QApplication::style()->standardPalette();
|
||||
}
|
||||
|
||||
setStyleFromSettings();
|
||||
setIconThemeFromStyle();
|
||||
}
|
||||
|
||||
void MainWindow::setStyleFromSettings()
|
||||
{
|
||||
const std::string theme(Host::GetBaseStringSettingValue("UI", "Theme", DEFAULT_THEME_NAME));
|
||||
|
||||
if (theme == "fusion")
|
||||
{
|
||||
qApp->setPalette(s_unthemed_palette);
|
||||
qApp->setStyleSheet(QString());
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
}
|
||||
else if (theme == "darkfusion")
|
||||
{
|
||||
// adapted from https://gist.github.com/QuantumCD/6245215
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor lighterGray(75, 75, 75);
|
||||
const QColor darkGray(53, 53, 53);
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor blue(198, 238, 255);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkGray);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, black);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, blue);
|
||||
darkPalette.setColor(QPalette::Highlight, lighterGray);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "darkfusionblue")
|
||||
{
|
||||
// adapted from https://gist.github.com/QuantumCD/6245215
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor darkGray(53, 53, 53);
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor blue(198, 238, 255);
|
||||
const QColor blue2(0, 88, 208);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkGray);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, black);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, blue2);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, blue);
|
||||
darkPalette.setColor(QPalette::Highlight, blue2);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "UntouchedLagoon")
|
||||
{
|
||||
// Custom palette by RedDevilus, Tame (Light/Washed out) Green as main color and Grayish Blue as complimentary.
|
||||
// Alternative white theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor darkteal(0, 77, 77);
|
||||
const QColor teal(0, 128, 128);
|
||||
const QColor tameTeal(160, 190, 185);
|
||||
const QColor grayBlue(160, 180, 190);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, tameTeal);
|
||||
standardPalette.setColor(QPalette::WindowText, black.lighter());
|
||||
standardPalette.setColor(QPalette::Base, grayBlue);
|
||||
standardPalette.setColor(QPalette::AlternateBase, tameTeal);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, tameTeal);
|
||||
standardPalette.setColor(QPalette::ToolTipText, grayBlue);
|
||||
standardPalette.setColor(QPalette::Text, black);
|
||||
standardPalette.setColor(QPalette::Button, tameTeal);
|
||||
standardPalette.setColor(QPalette::ButtonText, black);
|
||||
standardPalette.setColor(QPalette::Link, black.lighter());
|
||||
standardPalette.setColor(QPalette::Highlight, teal);
|
||||
standardPalette.setColor(QPalette::HighlightedText, grayBlue.lighter());
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, tameTeal);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkteal);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkteal.lighter());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkteal.lighter());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, tameTeal);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "BabyPastel")
|
||||
{
|
||||
// Custom palette by RedDevilus, Blue as main color and blue as complimentary.
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(150, 150, 150);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor redpinkish(200, 75, 132);
|
||||
const QColor pink(255, 174, 201);
|
||||
const QColor brightPink(255, 230, 255);
|
||||
const QColor congoPink(255, 127, 121);
|
||||
const QColor blue(221, 225, 239);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, pink);
|
||||
standardPalette.setColor(QPalette::WindowText, black);
|
||||
standardPalette.setColor(QPalette::Base, brightPink);
|
||||
standardPalette.setColor(QPalette::AlternateBase, blue);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, pink);
|
||||
standardPalette.setColor(QPalette::ToolTipText, brightPink);
|
||||
standardPalette.setColor(QPalette::Text, black);
|
||||
standardPalette.setColor(QPalette::Button, pink);
|
||||
standardPalette.setColor(QPalette::ButtonText, black);
|
||||
standardPalette.setColor(QPalette::Link, black);
|
||||
standardPalette.setColor(QPalette::Highlight, congoPink);
|
||||
standardPalette.setColor(QPalette::HighlightedText, black);
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, pink);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "PizzaBrown")
|
||||
{
|
||||
// Custom palette by KamFretoZ, a Pizza Tower Reference!
|
||||
// With a mixtures of Light Brown, Peachy/Creamy White, Latte-like Color.
|
||||
// Thanks to Jordan for the idea :P
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor extr(248, 192, 88);
|
||||
const QColor main(233, 187, 147);
|
||||
const QColor comp(248, 230, 213);
|
||||
const QColor highlight(188, 100, 60);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, main);
|
||||
standardPalette.setColor(QPalette::WindowText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Base, comp);
|
||||
standardPalette.setColor(QPalette::AlternateBase, extr);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, comp);
|
||||
standardPalette.setColor(QPalette::ToolTipText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Text, Qt::black);
|
||||
standardPalette.setColor(QPalette::Button, extr);
|
||||
standardPalette.setColor(QPalette::ButtonText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Link, Qt::black);
|
||||
standardPalette.setColor(QPalette::Highlight, highlight);
|
||||
standardPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, extr);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.darker());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.darker());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, Qt::gray);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray.lighter());
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #cc3f18; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "PCSX2Blue")
|
||||
{
|
||||
// Custom palette by RedDevilus, White as main color and Blue as complimentary.
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor blackish(35, 35, 35);
|
||||
const QColor darkBlue(73, 97, 177);
|
||||
const QColor blue2(80, 120, 200);
|
||||
const QColor blue(106, 156, 255);
|
||||
const QColor lightBlue(130, 155, 241);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, blue2.lighter());
|
||||
standardPalette.setColor(QPalette::WindowText, blackish);
|
||||
standardPalette.setColor(QPalette::Base, lightBlue);
|
||||
standardPalette.setColor(QPalette::AlternateBase, blue2.lighter());
|
||||
standardPalette.setColor(QPalette::ToolTipBase, blue2);
|
||||
standardPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
standardPalette.setColor(QPalette::Text, blackish);
|
||||
standardPalette.setColor(QPalette::Button, blue);
|
||||
standardPalette.setColor(QPalette::ButtonText, blackish);
|
||||
standardPalette.setColor(QPalette::Link, darkBlue);
|
||||
standardPalette.setColor(QPalette::Highlight, Qt::white);
|
||||
standardPalette.setColor(QPalette::HighlightedText, blackish);
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, blue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, darkBlue);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "ScarletDevilRed")
|
||||
{
|
||||
// Custom palette by RedDevilus, Red as main color and Purple as complimentary.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor darkRed(80, 45, 69);
|
||||
const QColor purplishRed(120, 45, 69);
|
||||
const QColor brightRed(200, 45, 69);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkRed);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, purplishRed);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkRed);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkRed);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, purplishRed.darker());
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, brightRed);
|
||||
darkPalette.setColor(QPalette::Highlight, brightRed);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, purplishRed.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkRed);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "CobaltSky")
|
||||
{
|
||||
// Custom palette by KamFretoZ, A soothing deep royal blue
|
||||
// that are meant to be easy on the eyes as the main color.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(192, 192, 192);
|
||||
const QColor royalBlue(29, 41, 81);
|
||||
const QColor darkishBlue(17, 30, 108);
|
||||
const QColor highlight(36, 93, 218);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, royalBlue);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, royalBlue.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, highlight);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkishBlue);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "VioletAngelPurple")
|
||||
{
|
||||
// Custom palette by RedDevilus, Blue as main color and Purple as complimentary.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor blackishblue(50, 25, 70);
|
||||
const QColor darkerPurple(90, 30, 105);
|
||||
const QColor nauticalPurple(110, 30, 125);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, blackishblue);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, nauticalPurple);
|
||||
darkPalette.setColor(QPalette::AlternateBase, blackishblue);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, nauticalPurple);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, nauticalPurple.darker());
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Highlight, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, nauticalPurple.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, darkerPurple.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, nauticalPurple);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Ruby")
|
||||
{
|
||||
// Custom palette by Daisouji, Black as main color and Red as complimentary.
|
||||
// Alternative dark (black) theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor slate(18, 18, 18);
|
||||
const QColor rubyish(172, 21, 31);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, slate);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, slate.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
|
||||
darkPalette.setColor(QPalette::ToolTipBase, slate);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, rubyish);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Sapphire")
|
||||
{
|
||||
// Custom palette by RedDevilus, Black as main color and Blue as complimentary.
|
||||
// Alternative dark (black) theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor slate(18, 18, 18);
|
||||
const QColor persianBlue(32, 35, 204);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, slate);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, slate.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
|
||||
darkPalette.setColor(QPalette::ToolTipBase, slate);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, persianBlue);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Custom")
|
||||
{
|
||||
|
||||
//Additional Theme option than loads .qss from main PCSX2 Directory
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
QString sheet_content;
|
||||
QFile sheets(QString::fromStdString(Path::Combine(EmuFolders::DataRoot, "custom.qss")));
|
||||
|
||||
if (sheets.open(QFile::ReadOnly))
|
||||
{
|
||||
QString sheet_content = QString::fromUtf8(sheets.readAll().data());
|
||||
qApp->setStyleSheet(sheet_content);
|
||||
}
|
||||
else
|
||||
{
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qApp->setPalette(s_unthemed_palette);
|
||||
qApp->setStyleSheet(QString());
|
||||
qApp->setStyle(s_unthemed_style_name);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setIconThemeFromStyle()
|
||||
{
|
||||
QPalette palette = qApp->palette();
|
||||
bool dark = palette.windowText().color().value() > palette.window().color().value();
|
||||
QIcon::setThemeName(dark ? QStringLiteral("white") : QStringLiteral("black"));
|
||||
}
|
||||
|
||||
void MainWindow::onScreenshotActionTriggered()
|
||||
{
|
||||
@@ -1574,7 +1118,11 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
||||
if (m_ui.menuDebug->menuAction()->isVisible())
|
||||
{
|
||||
action = menu.addAction(tr("Boot and Debug"));
|
||||
connect(action, &QAction::triggered, [this, entry]() { DebugInterface::setPauseOnEntry(true); startGameListEntry(entry); getDebuggerWindow()->show(); });
|
||||
connect(action, &QAction::triggered, [this, entry]() {
|
||||
DebugInterface::setPauseOnEntry(true);
|
||||
startGameListEntry(entry);
|
||||
getDebuggerWindow()->show();
|
||||
});
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
@@ -1838,7 +1386,7 @@ void MainWindow::onToolsCoverDownloaderTriggered()
|
||||
|
||||
void MainWindow::updateTheme()
|
||||
{
|
||||
updateApplicationTheme();
|
||||
QtHost::UpdateApplicationTheme();
|
||||
m_game_list_widget->refreshImages();
|
||||
}
|
||||
|
||||
|
||||
@@ -77,9 +77,6 @@ public:
|
||||
bool m_was_fullscreen;
|
||||
};
|
||||
|
||||
/// Default theme name for the platform.
|
||||
static const char* DEFAULT_THEME_NAME;
|
||||
|
||||
/// Default filter for opening a file.
|
||||
static const char* OPEN_FILE_FILTER;
|
||||
|
||||
@@ -90,9 +87,6 @@ public:
|
||||
MainWindow();
|
||||
~MainWindow();
|
||||
|
||||
/// Sets application theme according to settings.
|
||||
static void updateApplicationTheme();
|
||||
|
||||
void initialize();
|
||||
void connectVMThreadSignals(EmuThread* thread);
|
||||
void startupUpdateCheck();
|
||||
|
||||
@@ -438,16 +438,28 @@
|
||||
<property name="text">
|
||||
<string>&GitHub Repository...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="github">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSupportForums">
|
||||
<property name="text">
|
||||
<string>Support &Forums...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="at">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDiscordServer">
|
||||
<property name="text">
|
||||
<string>&Discord Server...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="discord">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCheckForUpdates">
|
||||
<property name="icon">
|
||||
@@ -471,6 +483,10 @@
|
||||
<property name="text">
|
||||
<string>&About PCSX2...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources/resources.qrc">
|
||||
<normaloff>:/icons/AppIcon.png</normaloff>:/icons/AppIcon.png</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionChangeDisc">
|
||||
<property name="icon">
|
||||
|
||||
@@ -1250,7 +1250,7 @@ void Host::SetDefaultUISettings(SettingsInterface& si)
|
||||
si.SetBoolValue("UI", "RenderToSeparateWindow", false);
|
||||
si.SetBoolValue("UI", "HideMainWindowWhenRunning", false);
|
||||
si.SetBoolValue("UI", "DisableWindowResize", false);
|
||||
si.SetStringValue("UI", "Theme", MainWindow::DEFAULT_THEME_NAME);
|
||||
si.SetStringValue("UI", "Theme", QtHost::GetDefaultThemeName());
|
||||
}
|
||||
|
||||
void QtHost::SaveSettings()
|
||||
@@ -1797,7 +1797,7 @@ int main(int argc, char* argv[])
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
// Set theme before creating any windows.
|
||||
MainWindow::updateApplicationTheme();
|
||||
QtHost::UpdateApplicationTheme();
|
||||
MainWindow* main_window = new MainWindow();
|
||||
|
||||
// Start up the CPU thread.
|
||||
|
||||
@@ -213,6 +213,12 @@ extern EmuThread* g_emu_thread;
|
||||
|
||||
namespace QtHost
|
||||
{
|
||||
/// Default theme name for the platform.
|
||||
const char* GetDefaultThemeName();
|
||||
|
||||
/// Sets application theme according to settings.
|
||||
void UpdateApplicationTheme();
|
||||
|
||||
/// Sets batch mode (exit after game shutdown).
|
||||
bool InBatchMode();
|
||||
|
||||
|
||||
@@ -37,13 +37,19 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||
#ifdef SDL_BUILD
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLRawInput, "InputSources", "SDLRawInput", false);
|
||||
connect(m_ui.enableSDLSource, &QCheckBox::stateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
|
||||
connect(m_ui.ledSettings, &QToolButton::clicked, this, &ControllerGlobalSettingsWidget::ledSettingsClicked);
|
||||
#else
|
||||
m_ui.enableSDLSource->setEnabled(false);
|
||||
m_ui.ledSettings->setEnabled(false);
|
||||
m_ui.enableSDLRawInput->setEnabled(false);
|
||||
#endif
|
||||
|
||||
#if defined(SDL_BUILD) && defined(_WIN32)
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLRawInput, "InputSources", "SDLRawInput", false);
|
||||
#else
|
||||
m_ui.gridLayout_2->removeWidget(m_ui.enableSDLRawInput);
|
||||
m_ui.enableSDLRawInput->deleteLater();
|
||||
m_ui.enableSDLRawInput = nullptr;
|
||||
#endif
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableMouseMapping, "UI", "EnableMouseMapping", false);
|
||||
@@ -62,7 +68,6 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||
m_ui.mainLayout->removeWidget(m_ui.dinputGroup);
|
||||
m_ui.dinputGroup->deleteLater();
|
||||
m_ui.dinputGroup = nullptr;
|
||||
m_ui.enableSDLRawInput->hide();
|
||||
#endif
|
||||
|
||||
if (dialog->isEditingProfile())
|
||||
@@ -116,7 +121,9 @@ void ControllerGlobalSettingsWidget::updateSDLOptionsEnabled()
|
||||
const bool enabled = m_ui.enableSDLSource->isChecked();
|
||||
m_ui.enableSDLEnhancedMode->setEnabled(enabled);
|
||||
m_ui.ledSettings->setEnabled(enabled);
|
||||
#ifdef _WIN32
|
||||
m_ui.enableSDLRawInput->setEnabled(enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ControllerGlobalSettingsWidget::ledSettingsClicked()
|
||||
|
||||
@@ -662,7 +662,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.osdShowGSStats, tr("Show Statistics"), tr("Unchecked"),
|
||||
tr("Shows counters for internal graphical utilization, useful for debugging."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowIndicators, tr("Show Indicators"), tr("Unchecked"),
|
||||
dialog->registerWidgetHelp(m_ui.osdShowIndicators, tr("Show Indicators"), tr("Checked"),
|
||||
tr("Shows OSD icon indicators for emulation states such as Pausing, Turbo, Fast-Forward, and Slow-Motion."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowSettings, tr("Show Settings"), tr("Unchecked"),
|
||||
|
||||
@@ -20,11 +20,12 @@
|
||||
#include "MainWindow.h"
|
||||
#include "SettingWidgetBinder.h"
|
||||
#include "SettingsDialog.h"
|
||||
#include "QtHost.h"
|
||||
|
||||
static const char* THEME_NAMES[] = {
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Native"),
|
||||
//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated.
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Fusion [Light]"),
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Fusion [Light/Dark]"),
|
||||
//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated.
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Dark Fusion (Gray) [Dark]"),
|
||||
//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated.
|
||||
@@ -91,7 +92,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
connect(m_ui.renderToSeparateWindow, &QCheckBox::stateChanged, this, &InterfaceSettingsWidget::onRenderToSeparateWindowChanged);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.theme, "UI", "Theme", THEME_NAMES, THEME_VALUES,
|
||||
MainWindow::DEFAULT_THEME_NAME);
|
||||
QtHost::GetDefaultThemeName());
|
||||
connect(m_ui.theme, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() { emit themeChanged(); });
|
||||
|
||||
// Per-game settings is special, we don't want to bind it if we're editing per-game settings.
|
||||
|
||||
@@ -0,0 +1,495 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "QtHost.h"
|
||||
|
||||
#include "pcsx2/Config.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
|
||||
#include "common/Path.h"
|
||||
|
||||
#include <QtGui/QPalette>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QStyle>
|
||||
#include <QtWidgets/QStyleFactory>
|
||||
|
||||
namespace QtHost
|
||||
{
|
||||
static void SetStyleFromSettings();
|
||||
static void SetIconThemeFromStyle();
|
||||
} // namespace QtHost
|
||||
|
||||
static QString s_unthemed_style_name;
|
||||
static bool s_unthemed_style_name_set;
|
||||
|
||||
const char* QtHost::GetDefaultThemeName()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
return "";
|
||||
#else
|
||||
return "darkfusion";
|
||||
#endif
|
||||
}
|
||||
|
||||
void QtHost::UpdateApplicationTheme()
|
||||
{
|
||||
if (!s_unthemed_style_name_set)
|
||||
{
|
||||
s_unthemed_style_name_set = true;
|
||||
s_unthemed_style_name = QApplication::style()->objectName();
|
||||
}
|
||||
|
||||
SetStyleFromSettings();
|
||||
SetIconThemeFromStyle();
|
||||
}
|
||||
|
||||
void QtHost::SetStyleFromSettings()
|
||||
{
|
||||
const std::string theme(Host::GetBaseStringSettingValue("UI", "Theme", GetDefaultThemeName()));
|
||||
|
||||
if (theme == "fusion")
|
||||
{
|
||||
// setPalette() shouldn't be necessary, as the documentation claims that setStyle() resets the palette, but it
|
||||
// is here, to work around a bug in 6.4.x and 6.5.x where the palette doesn't restore after changing themes.
|
||||
qApp->setPalette(QPalette());
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "darkfusion")
|
||||
{
|
||||
// adapted from https://gist.github.com/QuantumCD/6245215
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor lighterGray(75, 75, 75);
|
||||
const QColor darkGray(53, 53, 53);
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor blue(198, 238, 255);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkGray);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, black);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, blue);
|
||||
darkPalette.setColor(QPalette::Highlight, lighterGray);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "darkfusionblue")
|
||||
{
|
||||
// adapted from https://gist.github.com/QuantumCD/6245215
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor darkGray(53, 53, 53);
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor blue(198, 238, 255);
|
||||
const QColor blue2(0, 88, 208);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkGray);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, black);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, blue2);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, blue);
|
||||
darkPalette.setColor(QPalette::Highlight, blue2);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "UntouchedLagoon")
|
||||
{
|
||||
// Custom palette by RedDevilus, Tame (Light/Washed out) Green as main color and Grayish Blue as complimentary.
|
||||
// Alternative white theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor darkteal(0, 77, 77);
|
||||
const QColor teal(0, 128, 128);
|
||||
const QColor tameTeal(160, 190, 185);
|
||||
const QColor grayBlue(160, 180, 190);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, tameTeal);
|
||||
standardPalette.setColor(QPalette::WindowText, black.lighter());
|
||||
standardPalette.setColor(QPalette::Base, grayBlue);
|
||||
standardPalette.setColor(QPalette::AlternateBase, tameTeal);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, tameTeal);
|
||||
standardPalette.setColor(QPalette::ToolTipText, grayBlue);
|
||||
standardPalette.setColor(QPalette::Text, black);
|
||||
standardPalette.setColor(QPalette::Button, tameTeal);
|
||||
standardPalette.setColor(QPalette::ButtonText, black);
|
||||
standardPalette.setColor(QPalette::Link, black.lighter());
|
||||
standardPalette.setColor(QPalette::Highlight, teal);
|
||||
standardPalette.setColor(QPalette::HighlightedText, grayBlue.lighter());
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, tameTeal);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkteal);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkteal.lighter());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkteal.lighter());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, tameTeal);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "BabyPastel")
|
||||
{
|
||||
// Custom palette by RedDevilus, Blue as main color and blue as complimentary.
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(150, 150, 150);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor redpinkish(200, 75, 132);
|
||||
const QColor pink(255, 174, 201);
|
||||
const QColor brightPink(255, 230, 255);
|
||||
const QColor congoPink(255, 127, 121);
|
||||
const QColor blue(221, 225, 239);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, pink);
|
||||
standardPalette.setColor(QPalette::WindowText, black);
|
||||
standardPalette.setColor(QPalette::Base, brightPink);
|
||||
standardPalette.setColor(QPalette::AlternateBase, blue);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, pink);
|
||||
standardPalette.setColor(QPalette::ToolTipText, brightPink);
|
||||
standardPalette.setColor(QPalette::Text, black);
|
||||
standardPalette.setColor(QPalette::Button, pink);
|
||||
standardPalette.setColor(QPalette::ButtonText, black);
|
||||
standardPalette.setColor(QPalette::Link, black);
|
||||
standardPalette.setColor(QPalette::Highlight, congoPink);
|
||||
standardPalette.setColor(QPalette::HighlightedText, black);
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, pink);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "PizzaBrown")
|
||||
{
|
||||
// Custom palette by KamFretoZ, a Pizza Tower Reference!
|
||||
// With a mixtures of Light Brown, Peachy/Creamy White, Latte-like Color.
|
||||
// Thanks to Jordan for the idea :P
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor extr(248, 192, 88);
|
||||
const QColor main(233, 187, 147);
|
||||
const QColor comp(248, 230, 213);
|
||||
const QColor highlight(188, 100, 60);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, main);
|
||||
standardPalette.setColor(QPalette::WindowText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Base, comp);
|
||||
standardPalette.setColor(QPalette::AlternateBase, extr);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, comp);
|
||||
standardPalette.setColor(QPalette::ToolTipText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Text, Qt::black);
|
||||
standardPalette.setColor(QPalette::Button, extr);
|
||||
standardPalette.setColor(QPalette::ButtonText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Link, Qt::black);
|
||||
standardPalette.setColor(QPalette::Highlight, highlight);
|
||||
standardPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, extr);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.darker());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.darker());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, Qt::gray);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray.lighter());
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #cc3f18; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "PCSX2Blue")
|
||||
{
|
||||
// Custom palette by RedDevilus, White as main color and Blue as complimentary.
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor blackish(35, 35, 35);
|
||||
const QColor darkBlue(73, 97, 177);
|
||||
const QColor blue2(80, 120, 200);
|
||||
const QColor blue(106, 156, 255);
|
||||
const QColor lightBlue(130, 155, 241);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, blue2.lighter());
|
||||
standardPalette.setColor(QPalette::WindowText, blackish);
|
||||
standardPalette.setColor(QPalette::Base, lightBlue);
|
||||
standardPalette.setColor(QPalette::AlternateBase, blue2.lighter());
|
||||
standardPalette.setColor(QPalette::ToolTipBase, blue2);
|
||||
standardPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
standardPalette.setColor(QPalette::Text, blackish);
|
||||
standardPalette.setColor(QPalette::Button, blue);
|
||||
standardPalette.setColor(QPalette::ButtonText, blackish);
|
||||
standardPalette.setColor(QPalette::Link, darkBlue);
|
||||
standardPalette.setColor(QPalette::Highlight, Qt::white);
|
||||
standardPalette.setColor(QPalette::HighlightedText, blackish);
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, blue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, darkBlue);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "ScarletDevilRed")
|
||||
{
|
||||
// Custom palette by RedDevilus, Red as main color and Purple as complimentary.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor darkRed(80, 45, 69);
|
||||
const QColor purplishRed(120, 45, 69);
|
||||
const QColor brightRed(200, 45, 69);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkRed);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, purplishRed);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkRed);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkRed);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, purplishRed.darker());
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, brightRed);
|
||||
darkPalette.setColor(QPalette::Highlight, brightRed);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, purplishRed.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkRed);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "CobaltSky")
|
||||
{
|
||||
// Custom palette by KamFretoZ, A soothing deep royal blue
|
||||
// that are meant to be easy on the eyes as the main color.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(150, 150, 150);
|
||||
const QColor royalBlue(29, 41, 81);
|
||||
const QColor darkishBlue(17, 30, 108);
|
||||
const QColor highlight(36, 93, 218);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, royalBlue);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, royalBlue.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, highlight);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkishBlue);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "VioletAngelPurple")
|
||||
{
|
||||
// Custom palette by RedDevilus, Blue as main color and Purple as complimentary.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor blackishblue(50, 25, 70);
|
||||
const QColor darkerPurple(90, 30, 105);
|
||||
const QColor nauticalPurple(110, 30, 125);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, blackishblue);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, nauticalPurple);
|
||||
darkPalette.setColor(QPalette::AlternateBase, blackishblue);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, nauticalPurple);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, nauticalPurple.darker());
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Highlight, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, nauticalPurple.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, darkerPurple.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, nauticalPurple);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Ruby")
|
||||
{
|
||||
// Custom palette by Daisouji, Black as main color and Red as complimentary.
|
||||
// Alternative dark (black) theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor slate(18, 18, 18);
|
||||
const QColor rubyish(172, 21, 31);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, slate);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, slate.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
|
||||
darkPalette.setColor(QPalette::ToolTipBase, slate);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, rubyish);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Sapphire")
|
||||
{
|
||||
// Custom palette by RedDevilus, Black as main color and Blue as complimentary.
|
||||
// Alternative dark (black) theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor slate(18, 18, 18);
|
||||
const QColor persianBlue(32, 35, 204);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, slate);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, slate.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
|
||||
darkPalette.setColor(QPalette::ToolTipBase, slate);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, persianBlue);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Custom")
|
||||
{
|
||||
//Additional Theme option than loads .qss from main PCSX2 Directory
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
QString sheet_content;
|
||||
QFile sheets(QString::fromStdString(Path::Combine(EmuFolders::DataRoot, "custom.qss")));
|
||||
|
||||
if (sheets.open(QFile::ReadOnly))
|
||||
{
|
||||
QString sheet_content = QString::fromUtf8(sheets.readAll().data());
|
||||
qApp->setStyleSheet(sheet_content);
|
||||
}
|
||||
else
|
||||
{
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// setPalette() shouldn't be necessary, as the documentation claims that setStyle() resets the palette, but it
|
||||
// is here, to work around a bug in 6.4.x and 6.5.x where the palette doesn't restore after changing themes.
|
||||
qApp->setPalette(QPalette());
|
||||
qApp->setStyle(s_unthemed_style_name);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
}
|
||||
|
||||
void QtHost::SetIconThemeFromStyle()
|
||||
{
|
||||
QPalette palette = qApp->palette();
|
||||
bool dark = palette.windowText().color().value() > palette.window().color().value();
|
||||
QIcon::setThemeName(dark ? QStringLiteral("white") : QStringLiteral("black"));
|
||||
}
|
||||
@@ -144,6 +144,7 @@
|
||||
<ClCompile Include="Settings\DebugSettingsWidget.cpp" />
|
||||
<ClCompile Include="Settings\FolderSettingsWidget.cpp" />
|
||||
<ClCompile Include="Settings\MemoryCardConvertWorker.cpp" />
|
||||
<ClCompile Include="Themes.cpp" />
|
||||
<ClCompile Include="Tools\InputRecording\InputRecordingViewer.cpp" />
|
||||
<ClCompile Include="Tools\InputRecording\NewInputRecordingDlg.cpp" />
|
||||
<ClCompile Include="Debugger\CpuWidget.cpp" />
|
||||
|
||||
@@ -315,6 +315,7 @@
|
||||
<ClCompile Include="$(IntDir)moc_ColorPickerButton.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Themes.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
|
||||
|
||||
@@ -5,7 +5,7 @@ IFS="
|
||||
|
||||
printf "<RCC>\n"
|
||||
printf "\t<qresource>\n"
|
||||
for i in $(find . -not -iname '*.sh' -not -iname '*.qrc' -type f | cut -d'/' -f2-99); do
|
||||
for i in $(find . -not -iname '.*' -not -iname '*.sh' -not -iname '*.qrc' -type f | cut -d'/' -f2-99 | sort -f); do
|
||||
printf "\t\t<file>%s</file>\n" "$i"
|
||||
done
|
||||
printf "\t</qresource>\n"
|
||||
|
||||
|
After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 700 B |
|
After Width: | Height: | Size: 1.2 KiB |
@@ -2,6 +2,10 @@
|
||||
Name=Black Icon Theme
|
||||
Comment=Black Icon Theme
|
||||
|
||||
[32]
|
||||
Size=32
|
||||
Type=Fixed
|
||||
|
||||
[svg]
|
||||
Size=64
|
||||
Type=Scalable
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-at" viewBox="0 0 16 16"> <path d="M13.106 7.222c0-2.967-2.249-5.032-5.482-5.032-3.35 0-5.646 2.318-5.646 5.702 0 3.493 2.235 5.708 5.762 5.708.862 0 1.689-.123 2.304-.335v-.862c-.43.199-1.354.328-2.29.328-2.926 0-4.813-1.88-4.813-4.798 0-2.844 1.921-4.881 4.594-4.881 2.735 0 4.608 1.688 4.608 4.156 0 1.682-.554 2.769-1.416 2.769-.492 0-.772-.28-.772-.76V5.206H8.923v.834h-.11c-.266-.595-.881-.964-1.6-.964-1.4 0-2.378 1.162-2.378 2.823 0 1.737.957 2.906 2.379 2.906.8 0 1.415-.39 1.709-1.087h.11c.081.67.703 1.148 1.503 1.148 1.572 0 2.57-1.415 2.57-3.643zm-7.177.704c0-1.197.54-1.907 1.456-1.907.93 0 1.524.738 1.524 1.907S8.308 9.84 7.371 9.84c-.895 0-1.442-.725-1.442-1.914z"/> </svg>
|
||||
|
After Width: | Height: | Size: 939 B |
|
Before Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 1.3 KiB |
@@ -2,6 +2,10 @@
|
||||
Name=White Icon Theme
|
||||
Comment=White Icon Theme
|
||||
|
||||
[32]
|
||||
Size=32
|
||||
Type=Fixed
|
||||
|
||||
[svg]
|
||||
Size=64
|
||||
Type=Scalable
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg style="color: white" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-at" viewBox="0 0 16 16"> <path d="M13.106 7.222c0-2.967-2.249-5.032-5.482-5.032-3.35 0-5.646 2.318-5.646 5.702 0 3.493 2.235 5.708 5.762 5.708.862 0 1.689-.123 2.304-.335v-.862c-.43.199-1.354.328-2.29.328-2.926 0-4.813-1.88-4.813-4.798 0-2.844 1.921-4.881 4.594-4.881 2.735 0 4.608 1.688 4.608 4.156 0 1.682-.554 2.769-1.416 2.769-.492 0-.772-.28-.772-.76V5.206H8.923v.834h-.11c-.266-.595-.881-.964-1.6-.964-1.4 0-2.378 1.162-2.378 2.823 0 1.737.957 2.906 2.379 2.906.8 0 1.415-.39 1.709-1.087h.11c.081.67.703 1.148 1.503 1.148 1.572 0 2.57-1.415 2.57-3.643zm-7.177.704c0-1.197.54-1.907 1.456-1.907.93 0 1.524.738 1.524 1.907S8.308 9.84 7.371 9.84c-.895 0-1.442-.725-1.442-1.914z" fill="white"></path> </svg>
|
||||
|
After Width: | Height: | Size: 978 B |
@@ -1,10 +1,13 @@
|
||||
<RCC>
|
||||
<qresource>
|
||||
<file>icons/address-book-new-22.png</file>
|
||||
<file>icons/AppIcon.png</file>
|
||||
<file>icons/applications-system-24.png</file>
|
||||
<file>icons/black/32/discord.png</file>
|
||||
<file>icons/black/32/github.png</file>
|
||||
<file>icons/black/index.theme</file>
|
||||
<file>icons/black/svg/arrow-left-right-line.svg</file>
|
||||
<file>icons/black/svg/artboard-2-line.svg</file>
|
||||
<file>icons/black/svg/at.svg</file>
|
||||
<file>icons/black/svg/book-open-line.svg</file>
|
||||
<file>icons/black/svg/brush-line.svg</file>
|
||||
<file>icons/black/svg/checkbox-multiple-blank-line.svg</file>
|
||||
@@ -56,16 +59,18 @@
|
||||
<file>icons/black/svg/usb-fill.svg</file>
|
||||
<file>icons/black/svg/volume-up-line.svg</file>
|
||||
<file>icons/black/svg/window-2-line.svg</file>
|
||||
<file>icons/discord.png</file>
|
||||
<file>icons/logo.png</file>
|
||||
<file>icons/media-optical-24.png</file>
|
||||
<file>icons/media-optical-gear-24.png</file>
|
||||
<file>icons/media-optical.png</file>
|
||||
<file>icons/QT.png</file>
|
||||
<file>icons/update.png</file>
|
||||
<file>icons/white/32/discord.png</file>
|
||||
<file>icons/white/32/github.png</file>
|
||||
<file>icons/white/index.theme</file>
|
||||
<file>icons/white/svg/arrow-left-right-line.svg</file>
|
||||
<file>icons/white/svg/artboard-2-line.svg</file>
|
||||
<file>icons/white/svg/at.svg</file>
|
||||
<file>icons/white/svg/book-open-line.svg</file>
|
||||
<file>icons/white/svg/brush-line.svg</file>
|
||||
<file>icons/white/svg/checkbox-multiple-blank-line.svg</file>
|
||||
|
||||
@@ -253,7 +253,7 @@ bool InputIsoFile::Open(std::string srcfile, bool testOnly)
|
||||
|
||||
if (!detected)
|
||||
{
|
||||
Console.Error(fmt::format("Unable to identify the ISO image type for '{}'", srcfile));
|
||||
Console.Error(fmt::format("Unable to identify the ISO image type for '{}'", m_filename));
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -566,7 +566,6 @@ set(pcsx2GSHeaders
|
||||
GS/Renderers/Common/GSRenderer.h
|
||||
GS/Renderers/Common/GSTexture.h
|
||||
GS/Renderers/Common/GSVertex.h
|
||||
GS/Renderers/Common/GSVertexList.h
|
||||
GS/Renderers/Common/GSVertexTrace.h
|
||||
GS/Renderers/Null/GSRendererNull.h
|
||||
GS/Renderers/HW/GSHwHack.h
|
||||
@@ -1250,7 +1249,7 @@ function(setup_main_executable target)
|
||||
install(FILES $<TARGET_PDB_FILE:${target}> DESTINATION ${CMAKE_SOURCE_DIR}/bin)
|
||||
endif()
|
||||
find_program(WINDEPLOYQT_EXE windeployqt HINTS "${QT_BINARY_DIRECTORY}")
|
||||
install(CODE "execute_process(COMMAND \"${WINDEPLOYQT_EXE}\" \"${CMAKE_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${target}>\" --plugindir ${CMAKE_SOURCE_DIR}/bin/QtPlugins --no-compiler-runtime --no-system-d3d-compiler)")
|
||||
install(CODE "execute_process(COMMAND \"${WINDEPLOYQT_EXE}\" \"${CMAKE_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${target}>\" --plugindir \"${CMAKE_SOURCE_DIR}/bin/QtPlugins\" --no-compiler-runtime --no-system-d3d-compiler COMMAND_ERROR_IS_FATAL ANY)")
|
||||
install(CODE "file(WRITE \"${CMAKE_SOURCE_DIR}/bin/qt.conf\" \"[Paths]\\nPlugins = ./QtPlugins\")")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -598,6 +598,12 @@ u32 R5900DebugInterface::getPC()
|
||||
return cpuRegs.pc;
|
||||
}
|
||||
|
||||
// Taken from COP0.cpp
|
||||
bool R5900DebugInterface::getCPCOND0()
|
||||
{
|
||||
return (((dmacRegs.stat.CIS | ~dmacRegs.pcr.CPC) & 0x3FF) == 0x3ff);
|
||||
}
|
||||
|
||||
void R5900DebugInterface::setPc(u32 newPc)
|
||||
{
|
||||
cpuRegs.pc = newPc;
|
||||
@@ -945,6 +951,11 @@ u32 R3000DebugInterface::getPC()
|
||||
return psxRegs.pc;
|
||||
}
|
||||
|
||||
bool R3000DebugInterface::getCPCOND0()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void R3000DebugInterface::setPc(u32 newPc)
|
||||
{
|
||||
psxRegs.pc = newPc;
|
||||
|
||||
@@ -77,6 +77,7 @@ public:
|
||||
virtual u128 getHI() = 0;
|
||||
virtual u128 getLO() = 0;
|
||||
virtual u32 getPC() = 0;
|
||||
virtual bool getCPCOND0() = 0;
|
||||
virtual void setPc(u32 newPc) = 0;
|
||||
virtual void setRegister(int cat, int num, u128 newValue) = 0;
|
||||
|
||||
@@ -129,6 +130,7 @@ public:
|
||||
u128 getHI() override;
|
||||
u128 getLO() override;
|
||||
u32 getPC() override;
|
||||
bool getCPCOND0() override;
|
||||
void setPc(u32 newPc) override;
|
||||
void setRegister(int cat, int num, u128 newValue) override;
|
||||
[[nodiscard]] SymbolMap& GetSymbolMap() const override;
|
||||
@@ -168,6 +170,7 @@ public:
|
||||
u128 getHI() override;
|
||||
u128 getLO() override;
|
||||
u32 getPC() override;
|
||||
bool getCPCOND0() override;
|
||||
void setPc(u32 newPc) override;
|
||||
void setRegister(int cat, int num, u128 newValue) override;
|
||||
[[nodiscard]] SymbolMap& GetSymbolMap() const override;
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace MIPSAnalyst
|
||||
const R5900::OPCODE& opcode = R5900::GetInstruction(op);
|
||||
|
||||
int branchType = (opcode.flags & BRANCHTYPE_MASK);
|
||||
if ((opcode.flags & IS_BRANCH) && (branchType == BRANCHTYPE_BRANCH || branchType == BRANCHTYPE_BC1))
|
||||
if ((opcode.flags & IS_BRANCH) && (branchType == BRANCHTYPE_BRANCH || branchType == BRANCHTYPE_BC1 || branchType == BRANCHTYPE_BC0))
|
||||
return addr + 4 + ((signed short)(op&0xFFFF)<<2);
|
||||
else
|
||||
return INVALIDTARGET;
|
||||
@@ -71,7 +71,7 @@ namespace MIPSAnalyst
|
||||
const R5900::OPCODE& opcode = R5900::GetInstruction(op);
|
||||
|
||||
int branchType = (opcode.flags & BRANCHTYPE_MASK);
|
||||
if ((opcode.flags & IS_BRANCH) && (branchType == BRANCHTYPE_BRANCH || branchType == BRANCHTYPE_BC1))
|
||||
if ((opcode.flags & IS_BRANCH) && (branchType == BRANCHTYPE_BRANCH || branchType == BRANCHTYPE_BC1 || branchType == BRANCHTYPE_BC0))
|
||||
{
|
||||
if (!(opcode.flags & IS_LINKED))
|
||||
return addr + 4 + ((signed short)(op&0xFFFF)<<2);
|
||||
@@ -409,6 +409,20 @@ namespace MIPSAnalyst
|
||||
value = info.cpu->getRegister(EECAT_FCR,31)._u32[0] & 0x00800000;
|
||||
info.branchTarget = info.opcodeAddress + 4 + ((s16)(op&0xFFFF)<<2);
|
||||
|
||||
switch (opcode.flags & CONDTYPE_MASK)
|
||||
{
|
||||
case CONDTYPE_EQ:
|
||||
info.conditionMet = value == 0;
|
||||
break;
|
||||
case CONDTYPE_NE:
|
||||
info.conditionMet = value != 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BRANCHTYPE_BC0:
|
||||
info.isConditional = true;
|
||||
value = info.cpu->getCPCOND0();
|
||||
info.branchTarget = info.opcodeAddress + 4 + ((s16)(op&0xFFFF)<<2);
|
||||
switch (opcode.flags & CONDTYPE_MASK)
|
||||
{
|
||||
case CONDTYPE_EQ:
|
||||
|
||||
@@ -38,6 +38,7 @@ SERIAL-12345: # !required! Serial number for the game, this is how games are loo
|
||||
- GIFFIFOHack
|
||||
- GoemonTlbHack
|
||||
- IbitHack
|
||||
- FullVU0SyncHack
|
||||
- VUSyncHack
|
||||
- VUOverflowHack
|
||||
- SoftwareRendererFMVHack
|
||||
@@ -220,6 +221,9 @@ These values are case-sensitive so take care. If you incorrectly specify a Game
|
||||
* `IbitHack`
|
||||
* VU I bit Hack avoid constant recompilation in some games (Scarface The World Is Yours, Crash Tag Team Racing).
|
||||
|
||||
* `FullVU0SyncHack`
|
||||
* Increase the synchronisation points between COP2 and VU0.
|
||||
|
||||
* `VUSyncHack`
|
||||
* Make the VU's run behind/in sync with the EE to fix some timing issues.
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
"VIFFIFOHack",
|
||||
"VuAddSubHack",
|
||||
"VUOverflowHack",
|
||||
"FullVU0SyncHack",
|
||||
"VUSyncHack",
|
||||
"XGKickHack"
|
||||
]
|
||||
|
||||
@@ -3748,6 +3748,8 @@ void FullscreenUI::DrawControllerSettingsPage()
|
||||
DrawToggleSetting(bsi, ICON_FA_WIFI " SDL DualShock 4 / DualSense Enhanced Mode",
|
||||
"Provides vibration and LED control support over Bluetooth.", "InputSources", "SDLControllerEnhancedMode", false,
|
||||
bsi->GetBoolValue("InputSources", "SDL", true), false);
|
||||
#endif
|
||||
#if defined(SDL_BUILD) && defined(_WIN32)
|
||||
DrawToggleSetting(bsi, ICON_FA_COG " SDL Raw Input", "Allow SDL to use raw access to input devices.", "InputSources", "SDLRawInput",
|
||||
false, bsi->GetBoolValue("InputSources", "SDL", true), false);
|
||||
#endif
|
||||
|
||||
@@ -516,7 +516,7 @@ void GSvsync(u32 field, bool registers_written)
|
||||
{
|
||||
try
|
||||
{
|
||||
g_gs_renderer->VSync(field, registers_written);
|
||||
g_gs_renderer->VSync(field, registers_written, g_gs_renderer->IsIdleFrame());
|
||||
}
|
||||
catch (GSRecoverableError)
|
||||
{
|
||||
@@ -748,12 +748,13 @@ void GSgetStats(std::string& info)
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(info), "{} HW | {} P | {} D | {} DC | {} B | {} RB | {} TC | {} TU",
|
||||
fmt::format_to(std::back_inserter(info), "{} HW | {} P | {} D | {} DC | {} B | {} RP | {} RB | {} TC | {} TU",
|
||||
api_name,
|
||||
(int)pm.Get(GSPerfMon::Prim),
|
||||
(int)pm.Get(GSPerfMon::Draw),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::DrawCalls)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Barriers)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::RenderPasses)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Readbacks)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureCopies)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureUploads)));
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GS/GSClut.h"
|
||||
#include "GS/GSExtra.h"
|
||||
#include "GS/GSLocalMemory.h"
|
||||
#include "GS/GSGL.h"
|
||||
#include "GS/Renderers/Common/GSDevice.h"
|
||||
@@ -27,7 +28,7 @@ GSClut::GSClut(GSLocalMemory* mem)
|
||||
static constexpr u32 CLUT_ALLOC_SIZE = 4096 * 2;
|
||||
|
||||
// 1k + 1k for mirrored area simulating wrapping memory
|
||||
m_clut = static_cast<u16*>(_aligned_malloc(CLUT_ALLOC_SIZE, 32));
|
||||
m_clut = static_cast<u16*>(_aligned_malloc(CLUT_ALLOC_SIZE, VECTOR_ALIGNMENT));
|
||||
if (!m_clut)
|
||||
throw std::bad_alloc();
|
||||
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSVector.h"
|
||||
#include "GS/GSVector.h"
|
||||
#include "pcsx2/Config.h"
|
||||
#include "common/Align.h"
|
||||
|
||||
/// Like `memcmp(&a, &b, sizeof(T)) == 0` but faster
|
||||
template <typename T>
|
||||
@@ -117,6 +118,17 @@ static constexpr u32 MAX_SKIPPED_DUPLICATE_FRAMES = 3;
|
||||
extern void* GSAllocateWrappedMemory(size_t size, size_t repeat);
|
||||
extern void GSFreeWrappedMemory(void* ptr, size_t size, size_t repeat);
|
||||
|
||||
/// We want all allocations and pitches to be aligned to 32-bit, regardless of whether we're
|
||||
/// SSE4 or AVX2, because of multi-ISA.
|
||||
static constexpr u32 VECTOR_ALIGNMENT = 32;
|
||||
|
||||
/// Aligns allocation/pitch size to preferred host size.
|
||||
template<typename T>
|
||||
__fi static T VectorAlign(T value)
|
||||
{
|
||||
return Common::AlignUpPow2(value, VECTOR_ALIGNMENT);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifdef __POSIX__
|
||||
|
||||
@@ -286,7 +286,7 @@ GSPixelOffset* GSLocalMemory::GetPixelOffset(const GIFRegFRAME& FRAME, const GIF
|
||||
return it->second;
|
||||
}
|
||||
|
||||
GSPixelOffset* off = (GSPixelOffset*)_aligned_malloc(sizeof(GSPixelOffset), 32);
|
||||
GSPixelOffset* off = (GSPixelOffset*)_aligned_malloc(sizeof(GSPixelOffset), VECTOR_ALIGNMENT);
|
||||
|
||||
off->hash = hash;
|
||||
off->fbp = fbp;
|
||||
@@ -339,7 +339,7 @@ GSPixelOffset4* GSLocalMemory::GetPixelOffset4(const GIFRegFRAME& FRAME, const G
|
||||
return it->second;
|
||||
}
|
||||
|
||||
GSPixelOffset4* off = (GSPixelOffset4*)_aligned_malloc(sizeof(GSPixelOffset4), 32);
|
||||
GSPixelOffset4* off = (GSPixelOffset4*)_aligned_malloc(sizeof(GSPixelOffset4), VECTOR_ALIGNMENT);
|
||||
|
||||
off->hash = hash;
|
||||
off->fbp = fbp;
|
||||
@@ -544,7 +544,7 @@ void GSLocalMemory::SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int
|
||||
{
|
||||
int pitch = w * 4;
|
||||
int size = pitch * h;
|
||||
void* bits = _aligned_malloc(size, 32);
|
||||
void* bits = _aligned_malloc(size, VECTOR_ALIGNMENT);
|
||||
|
||||
GIFRegTEX0 TEX0;
|
||||
|
||||
|
||||
@@ -19,8 +19,9 @@
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include "GSDump.h"
|
||||
#include "GSLzma.h"
|
||||
#include "GS/GSDump.h"
|
||||
#include "GS/GSLzma.h"
|
||||
#include "GS/GSExtra.h"
|
||||
|
||||
using namespace GSDumpTypes;
|
||||
|
||||
@@ -273,8 +274,8 @@ void GSDumpLzma::Initialize()
|
||||
}
|
||||
|
||||
m_buff_size = 1024*1024;
|
||||
m_area = (uint8_t*)_aligned_malloc(m_buff_size, 32);
|
||||
m_inbuf = (uint8_t*)_aligned_malloc(BUFSIZ, 32);
|
||||
m_area = (uint8_t*)_aligned_malloc(m_buff_size, VECTOR_ALIGNMENT);
|
||||
m_inbuf = (uint8_t*)_aligned_malloc(BUFSIZ, VECTOR_ALIGNMENT);
|
||||
m_avail = 0;
|
||||
m_start = 0;
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@ public:
|
||||
Swizzle,
|
||||
Unswizzle,
|
||||
Fillrate,
|
||||
Quad,
|
||||
SyncPoint,
|
||||
Barriers,
|
||||
RenderPasses,
|
||||
CounterLast,
|
||||
|
||||
// Reused counters for HW.
|
||||
|
||||
@@ -2638,31 +2638,31 @@ void GSState::GrowVertexBuffer()
|
||||
{
|
||||
const u32 maxcount = std::max<u32>(m_vertex.maxcount * 3 / 2, 10000);
|
||||
|
||||
GSVertex* vertex = (GSVertex*)_aligned_malloc(sizeof(GSVertex) * maxcount, 32);
|
||||
GSVertex* vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
|
||||
// Worst case index list is a list of points with vs expansion, 6 indices per point
|
||||
u32* index = (u32*)_aligned_malloc(sizeof(u32) * maxcount * 6, 32);
|
||||
u16* index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));
|
||||
|
||||
if (vertex == NULL || index == NULL)
|
||||
if (!vertex || !index)
|
||||
{
|
||||
const u32 vert_byte_count = sizeof(GSVertex) * maxcount;
|
||||
const u32 idx_byte_count = sizeof(u32) * maxcount * 3;
|
||||
const u32 idx_byte_count = sizeof(u16) * maxcount * 3;
|
||||
|
||||
Console.Error("GS: failed to allocate %zu bytes for verticles and %zu for indices.",
|
||||
Console.Error("GS: failed to allocate %zu bytes for vertices and %zu for indices.",
|
||||
vert_byte_count, idx_byte_count);
|
||||
|
||||
throw GSError();
|
||||
}
|
||||
|
||||
if (m_vertex.buff != NULL)
|
||||
if (m_vertex.buff)
|
||||
{
|
||||
memcpy(vertex, m_vertex.buff, sizeof(GSVertex) * m_vertex.tail);
|
||||
std::memcpy(vertex, m_vertex.buff, sizeof(GSVertex) * m_vertex.tail);
|
||||
|
||||
_aligned_free(m_vertex.buff);
|
||||
}
|
||||
|
||||
if (m_index.buff != NULL)
|
||||
if (m_index.buff)
|
||||
{
|
||||
memcpy(index, m_index.buff, sizeof(u32) * m_index.tail);
|
||||
std::memcpy(index, m_index.buff, sizeof(u16) * m_index.tail);
|
||||
|
||||
_aligned_free(m_index.buff);
|
||||
}
|
||||
@@ -3063,21 +3063,24 @@ static constexpr u32 MaxVerticesForPrim(u32 prim)
|
||||
{
|
||||
switch (prim)
|
||||
{
|
||||
// Four indices per 1 vertex.
|
||||
case GS_POINTLIST:
|
||||
case GS_INVALID:
|
||||
// Needed due to expansion in hardware renderers.
|
||||
|
||||
// Indices are shifted left by 2 to form quads.
|
||||
case GS_LINELIST:
|
||||
case GS_LINESTRIP:
|
||||
return (std::numeric_limits<u16>::max() / 4) - 4;
|
||||
|
||||
// Four indices per two vertices.
|
||||
case GS_SPRITE:
|
||||
return (std::numeric_limits<u16>::max() / 2) - 2;
|
||||
|
||||
case GS_LINELIST:
|
||||
case GS_LINESTRIP:
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
default:
|
||||
return 0;
|
||||
return (std::numeric_limits<u16>::max() - 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3229,19 +3232,19 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
m_backed_up_ctx = m_env.PRIM.CTXT;
|
||||
}
|
||||
|
||||
u32* RESTRICT buff = &m_index.buff[m_index.tail];
|
||||
u16* RESTRICT buff = &m_index.buff[m_index.tail];
|
||||
|
||||
switch (prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
buff[0] = head + 0;
|
||||
buff[0] = static_cast<u16>(head + 0);
|
||||
m_vertex.head = head + 1;
|
||||
m_vertex.next = head + 1;
|
||||
m_index.tail += 1;
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
buff[0] = head + (index_swap ? 1 : 0);
|
||||
buff[1] = head + (index_swap ? 0 : 1);
|
||||
buff[0] = static_cast<u16>(head + (index_swap ? 1 : 0));
|
||||
buff[1] = static_cast<u16>(head + (index_swap ? 0 : 1));
|
||||
m_vertex.head = head + 2;
|
||||
m_vertex.next = head + 2;
|
||||
m_index.tail += 2;
|
||||
@@ -3254,16 +3257,16 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
head = next;
|
||||
m_vertex.tail = next + 2;
|
||||
}
|
||||
buff[0] = head + (index_swap ? 1 : 0);
|
||||
buff[1] = head + (index_swap ? 0 : 1);
|
||||
buff[0] = static_cast<u16>(head + (index_swap ? 1 : 0));
|
||||
buff[1] = static_cast<u16>(head + (index_swap ? 0 : 1));
|
||||
m_vertex.head = head + 1;
|
||||
m_vertex.next = head + 2;
|
||||
m_index.tail += 2;
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
buff[0] = head + (index_swap ? 2 : 0);
|
||||
buff[1] = head + 1;
|
||||
buff[2] = head + (index_swap ? 0 : 2);
|
||||
buff[0] = static_cast<u16>(head + (index_swap ? 2 : 0));
|
||||
buff[1] = static_cast<u16>(head + 1);
|
||||
buff[2] = static_cast<u16>(head + (index_swap ? 0 : 2));
|
||||
m_vertex.head = head + 3;
|
||||
m_vertex.next = head + 3;
|
||||
m_index.tail += 3;
|
||||
@@ -3277,24 +3280,24 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
head = next;
|
||||
m_vertex.tail = next + 3;
|
||||
}
|
||||
buff[0] = head + (index_swap ? 2 : 0);
|
||||
buff[1] = head + 1;
|
||||
buff[2] = head + (index_swap ? 0 : 2);
|
||||
buff[0] = static_cast<u16>(head + (index_swap ? 2 : 0));
|
||||
buff[1] = static_cast<u16>(head + 1);
|
||||
buff[2] = static_cast<u16>(head + (index_swap ? 0 : 2));
|
||||
m_vertex.head = head + 1;
|
||||
m_vertex.next = head + 3;
|
||||
m_index.tail += 3;
|
||||
break;
|
||||
case GS_TRIANGLEFAN:
|
||||
// TODO: remove gaps, next == head && head < tail - 3 || next > head && next < tail - 2 (very rare)
|
||||
buff[0] = index_swap ? (tail - 1) : (head + 0);
|
||||
buff[1] = tail - 2;
|
||||
buff[2] = index_swap ? (head + 0) : (tail - 1);
|
||||
buff[0] = static_cast<u16>(index_swap ? (tail - 1) : (head + 0));
|
||||
buff[1] = static_cast<u16>(tail - 2);
|
||||
buff[2] = static_cast<u16>(index_swap ? (head + 0) : (tail - 1));
|
||||
m_vertex.next = tail;
|
||||
m_index.tail += 3;
|
||||
break;
|
||||
case GS_SPRITE:
|
||||
buff[0] = head + 0;
|
||||
buff[1] = head + 1;
|
||||
buff[0] = static_cast<u16>(head + 0);
|
||||
buff[1] = static_cast<u16>(head + 1);
|
||||
m_vertex.head = head + 2;
|
||||
m_vertex.next = head + 2;
|
||||
m_index.tail += 2;
|
||||
|
||||
@@ -158,7 +158,7 @@ protected:
|
||||
|
||||
struct
|
||||
{
|
||||
u32* buff;
|
||||
u16* buff;
|
||||
u32 tail;
|
||||
} m_index = {};
|
||||
|
||||
|
||||
@@ -28,6 +28,16 @@ class alignas(16) GSVector4i
|
||||
{
|
||||
}
|
||||
|
||||
constexpr GSVector4i(cxpr_init_tag, short s0, short s1, short s2, short s3, short s4, short s5, short s6, short s7)
|
||||
: I16{s0, s1, s2, s3, s4, s5, s6, s7}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr GSVector4i(cxpr_init_tag, char b0, char b1, char b2, char b3, char b4, char b5, char b6, char b7, char b8, char b9, char b10, char b11, char b12, char b13, char b14, char b15)
|
||||
: I8{b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15}
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
union
|
||||
{
|
||||
@@ -62,6 +72,16 @@ public:
|
||||
return GSVector4i(cxpr_init, x, x, x, x);
|
||||
}
|
||||
|
||||
constexpr static GSVector4i cxpr16(short s0, short s1, short s2, short s3, short s4, short s5, short s6, short s7)
|
||||
{
|
||||
return GSVector4i(cxpr_init, s0, s1, s2, s3, s4, s5, s6, s7);
|
||||
}
|
||||
|
||||
constexpr static GSVector4i cxpr8(char b0, char b1, char b2, char b3, char b4, char b5, char b6, char b7, char b8, char b9, char b10, char b11, char b12, char b13, char b14, char b15)
|
||||
{
|
||||
return GSVector4i(cxpr_init, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15);
|
||||
}
|
||||
|
||||
__forceinline GSVector4i(int x, int y, int z, int w)
|
||||
{
|
||||
m = _mm_set_epi32(w, z, y, x);
|
||||
@@ -2001,6 +2021,10 @@ public:
|
||||
return v;
|
||||
}
|
||||
|
||||
__forceinline static GSVector4i broadcast16(u16 value)
|
||||
{
|
||||
return GSVector4i(_mm_set1_epi16(value));
|
||||
}
|
||||
|
||||
__forceinline static GSVector4i zero() { return GSVector4i(_mm_setzero_si128()); }
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "GS/GSGL.h"
|
||||
#include "GS/GS.h"
|
||||
#include "Host.h"
|
||||
#include "common/Align.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include "imgui.h"
|
||||
@@ -90,7 +91,7 @@ GSDevice::GSDevice() = default;
|
||||
GSDevice::~GSDevice()
|
||||
{
|
||||
// should've been cleaned up in Destroy()
|
||||
pxAssert(m_pool.empty() && !m_merge && !m_weavebob && !m_blend && !m_mad && !m_target_tmp && !m_cas);
|
||||
pxAssert(m_pool[0].empty() && m_pool[1].empty() && !m_merge && !m_weavebob && !m_blend && !m_mad && !m_target_tmp && !m_cas);
|
||||
}
|
||||
|
||||
const char* GSDevice::RenderAPIToString(RenderAPI api)
|
||||
@@ -165,9 +166,9 @@ std::string GSDevice::GetFullscreenModeString(u32 width, u32 height, float refre
|
||||
|
||||
void GSDevice::GenerateExpansionIndexBuffer(void* buffer)
|
||||
{
|
||||
static constexpr u32 MAX_INDEX = std::numeric_limits<u16>::max();
|
||||
static constexpr u32 MAX_INDEX = EXPAND_BUFFER_SIZE / 6 / sizeof(u16);
|
||||
|
||||
u32* idx_buffer = static_cast<u32*>(buffer);
|
||||
u16* idx_buffer = static_cast<u16*>(buffer);
|
||||
for (u32 i = 0; i < MAX_INDEX; i++)
|
||||
{
|
||||
const u32 base = i * 4;
|
||||
@@ -247,11 +248,12 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
||||
{
|
||||
const GSVector2i size(width, height);
|
||||
const bool prefer_new_texture = (m_features.prefer_new_textures && type == GSTexture::Type::Texture && !prefer_reuse);
|
||||
FastList<GSTexture*>& pool = m_pool[type != GSTexture::Type::Texture];
|
||||
|
||||
GSTexture* t = nullptr;
|
||||
auto fallback = m_pool.end();
|
||||
auto fallback = pool.end();
|
||||
|
||||
for (auto i = m_pool.begin(); i != m_pool.end(); ++i)
|
||||
for (auto i = pool.begin(); i != pool.end(); ++i)
|
||||
{
|
||||
t = *i;
|
||||
|
||||
@@ -262,10 +264,10 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
||||
if (!prefer_new_texture || t->GetLastFrameUsed() != m_frame)
|
||||
{
|
||||
m_pool_memory_usage -= t->GetMemUsage();
|
||||
m_pool.erase(i);
|
||||
pool.erase(i);
|
||||
break;
|
||||
}
|
||||
else if (fallback == m_pool.end())
|
||||
else if (fallback == pool.end())
|
||||
{
|
||||
fallback = i;
|
||||
}
|
||||
@@ -276,11 +278,12 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
||||
|
||||
if (!t)
|
||||
{
|
||||
if (m_pool.size() >= MAX_POOLED_TEXTURES && fallback != m_pool.end())
|
||||
if (pool.size() >= ((type == GSTexture::Type::Texture) ? MAX_POOLED_TEXTURES : MAX_POOLED_TARGETS) &&
|
||||
fallback != pool.end())
|
||||
{
|
||||
t = *fallback;
|
||||
m_pool_memory_usage -= t->GetMemUsage();
|
||||
m_pool.erase(fallback);
|
||||
pool.erase(fallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -322,17 +325,24 @@ void GSDevice::Recycle(GSTexture* t)
|
||||
|
||||
t->SetLastFrameUsed(m_frame);
|
||||
|
||||
m_pool.push_front(t);
|
||||
FastList<GSTexture*>& pool = m_pool[!t->IsTexture()];
|
||||
pool.push_front(t);
|
||||
m_pool_memory_usage += t->GetMemUsage();
|
||||
|
||||
//printf("%d\n",m_pool.size());
|
||||
|
||||
while (m_pool.size() > MAX_POOLED_TEXTURES)
|
||||
const u32 max_size = t->IsTexture() ? MAX_POOLED_TEXTURES : MAX_POOLED_TARGETS;
|
||||
const u32 max_age = t->IsTexture() ? MAX_TEXTURE_AGE : MAX_TARGET_AGE;
|
||||
while (pool.size() > max_size)
|
||||
{
|
||||
m_pool_memory_usage -= m_pool.back()->GetMemUsage();
|
||||
delete m_pool.back();
|
||||
// Don't toss when the texture was last used in this frame.
|
||||
// Because we're going to need to keep it alive anyway.
|
||||
GSTexture* back = pool.back();
|
||||
if ((m_frame - back->GetLastFrameUsed()) < max_age)
|
||||
break;
|
||||
|
||||
m_pool.pop_back();
|
||||
m_pool_memory_usage -= back->GetMemUsage();
|
||||
delete back;
|
||||
|
||||
pool.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,20 +356,33 @@ void GSDevice::AgePool()
|
||||
{
|
||||
m_frame++;
|
||||
|
||||
while (m_pool.size() > 40 && m_frame - m_pool.back()->GetLastFrameUsed() > 10)
|
||||
// Toss out textures when they're not too-recently used.
|
||||
for (u32 pool_idx = 0; pool_idx < m_pool.size(); pool_idx++)
|
||||
{
|
||||
m_pool_memory_usage -= m_pool.back()->GetMemUsage();
|
||||
delete m_pool.back();
|
||||
const u32 max_age = (pool_idx == 0) ? MAX_TEXTURE_AGE : MAX_TARGET_AGE;
|
||||
FastList<GSTexture*>& pool = m_pool[pool_idx];
|
||||
while (!pool.empty())
|
||||
{
|
||||
GSTexture* back = pool.back();
|
||||
if ((m_frame - back->GetLastFrameUsed()) < max_age)
|
||||
break;
|
||||
|
||||
m_pool.pop_back();
|
||||
m_pool_memory_usage -= back->GetMemUsage();
|
||||
delete back;
|
||||
|
||||
pool.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice::PurgePool()
|
||||
{
|
||||
for (auto t : m_pool)
|
||||
delete t;
|
||||
m_pool.clear();
|
||||
for (FastList<GSTexture*>& pool : m_pool)
|
||||
{
|
||||
for (GSTexture* t : pool)
|
||||
delete t;
|
||||
pool.clear();
|
||||
}
|
||||
m_pool_memory_usage = 0;
|
||||
}
|
||||
|
||||
@@ -379,14 +402,6 @@ GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::F
|
||||
return FetchSurface(GSTexture::Type::Texture, w, h, levels, format, false, prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture::Format GSDevice::GetDefaultTextureFormat(GSTexture::Type type)
|
||||
{
|
||||
if (type == GSTexture::Type::DepthStencil)
|
||||
return GSTexture::Format::DepthStencil;
|
||||
else
|
||||
return GSTexture::Format::Color;
|
||||
}
|
||||
|
||||
void GSDevice::StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader, bool linear)
|
||||
{
|
||||
StretchRect(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, shader, linear);
|
||||
@@ -440,7 +455,7 @@ void GSDevice::ClearCurrent()
|
||||
|
||||
void GSDevice::Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c)
|
||||
{
|
||||
if (ResizeTarget(&m_merge, fs.x, fs.y))
|
||||
if (ResizeRenderTarget(&m_merge, fs.x, fs.y, false, false))
|
||||
DoMerge(sTex, sRect, m_merge, dRect, PMODE, EXTBUF, c, GSConfig.PCRTCOffsets);
|
||||
|
||||
m_current = m_merge;
|
||||
@@ -480,20 +495,20 @@ void GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffse
|
||||
switch (mode)
|
||||
{
|
||||
case 0: // Weave
|
||||
ResizeTarget(&m_weavebob, ds.x, ds.y);
|
||||
ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false);
|
||||
do_interlace(m_merge, m_weavebob, ShaderInterlace::WEAVE, false, offset, field);
|
||||
m_current = m_weavebob;
|
||||
break;
|
||||
case 1: // Bob
|
||||
// Field is reversed here as we are countering the bounce.
|
||||
ResizeTarget(&m_weavebob, ds.x, ds.y);
|
||||
ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false);
|
||||
do_interlace(m_merge, m_weavebob, ShaderInterlace::BOB, true, yoffset * (1 - field), 0);
|
||||
m_current = m_weavebob;
|
||||
break;
|
||||
case 2: // Blend
|
||||
ResizeTarget(&m_weavebob, ds.x, ds.y);
|
||||
ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false);
|
||||
do_interlace(m_merge, m_weavebob, ShaderInterlace::WEAVE, false, offset, field);
|
||||
ResizeTarget(&m_blend, ds.x, ds.y);
|
||||
ResizeRenderTarget(&m_blend, ds.x, ds.y, true, false);
|
||||
do_interlace(m_weavebob, m_blend, ShaderInterlace::BLEND, false, 0, 0);
|
||||
m_current = m_blend;
|
||||
break;
|
||||
@@ -502,9 +517,9 @@ void GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffse
|
||||
bufIdx &= ~1;
|
||||
bufIdx |= field;
|
||||
bufIdx &= 3;
|
||||
ResizeTarget(&m_mad, ds.x, ds.y * 2.0f);
|
||||
ResizeRenderTarget(&m_mad, ds.x, ds.y * 2.0f, true, false);
|
||||
do_interlace(m_merge, m_mad, ShaderInterlace::MAD_BUFFER, false, offset, bufIdx);
|
||||
ResizeTarget(&m_weavebob, ds.x, ds.y);
|
||||
ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false);
|
||||
do_interlace(m_mad, m_weavebob, ShaderInterlace::MAD_RECONSTRUCT, false, 0, bufIdx);
|
||||
m_current = m_weavebob;
|
||||
break;
|
||||
@@ -518,9 +533,8 @@ void GSDevice::FXAA()
|
||||
{
|
||||
// Combining FXAA+ShadeBoost can't share the same target.
|
||||
GSTexture*& dTex = (m_current == m_target_tmp) ? m_merge : m_target_tmp;
|
||||
if (ResizeTexture(&dTex, GSTexture::Type::RenderTarget, m_current->GetWidth(), m_current->GetHeight(), false, true))
|
||||
if (ResizeRenderTarget(&dTex, m_current->GetWidth(), m_current->GetHeight(), false, false))
|
||||
{
|
||||
InvalidateRenderTarget(dTex);
|
||||
DoFXAA(m_current, dTex);
|
||||
m_current = dTex;
|
||||
}
|
||||
@@ -528,10 +542,8 @@ void GSDevice::FXAA()
|
||||
|
||||
void GSDevice::ShadeBoost()
|
||||
{
|
||||
if (ResizeTexture(&m_target_tmp, GSTexture::Type::RenderTarget, m_current->GetWidth(), m_current->GetHeight(), false, true))
|
||||
if (ResizeRenderTarget(&m_target_tmp, m_current->GetWidth(), m_current->GetHeight(), false, false))
|
||||
{
|
||||
InvalidateRenderTarget(m_target_tmp);
|
||||
|
||||
// predivide to avoid the divide (multiply) in the shader
|
||||
const float params[4] = {
|
||||
static_cast<float>(GSConfig.ShadeBoost_Brightness) * (1.0f / 50.0f),
|
||||
@@ -556,7 +568,7 @@ void GSDevice::Resize(int width, int height)
|
||||
s = m_current->GetSize() * GSVector2i(++multiplier);
|
||||
}
|
||||
|
||||
if (ResizeTexture(&dTex, GSTexture::Type::RenderTarget, s.x, s.y, false))
|
||||
if (ResizeRenderTarget(&dTex, s.x, s.y, false, false))
|
||||
{
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0, 0, s.x, s.y);
|
||||
@@ -565,55 +577,48 @@ void GSDevice::Resize(int width, int height)
|
||||
}
|
||||
}
|
||||
|
||||
bool GSDevice::ResizeTexture(GSTexture** t, GSTexture::Type type, int w, int h, bool clear, bool prefer_reuse)
|
||||
bool GSDevice::ResizeRenderTarget(GSTexture** t, int w, int h, bool preserve_contents, bool recycle)
|
||||
{
|
||||
if (t == NULL)
|
||||
pxAssert(t);
|
||||
|
||||
GSTexture* orig_tex = *t;
|
||||
if (orig_tex && orig_tex->GetWidth() == w && orig_tex->GetHeight() == h)
|
||||
{
|
||||
ASSERT(0);
|
||||
if (!preserve_contents)
|
||||
InvalidateRenderTarget(orig_tex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GSTexture* new_tex;
|
||||
try
|
||||
{
|
||||
const GSTexture::Format fmt = orig_tex ? orig_tex->GetFormat() : GSTexture::Format::Color;
|
||||
new_tex = FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, fmt, !preserve_contents, true);
|
||||
}
|
||||
catch (std::bad_alloc&)
|
||||
{
|
||||
Console.WriteLn("%dx%d texture allocation failed in ResizeTexture()", w, h);
|
||||
return false;
|
||||
}
|
||||
|
||||
GSTexture* t2 = *t;
|
||||
|
||||
if (t2 == NULL || t2->GetWidth() != w || t2->GetHeight() != h)
|
||||
if (preserve_contents && orig_tex)
|
||||
{
|
||||
const GSTexture::Format fmt = t2 ? t2->GetFormat() : GetDefaultTextureFormat(type);
|
||||
const int levels = t2 ? (t2->IsMipmap() ? MipmapLevelsForSize(w, h) : 1) : 1;
|
||||
|
||||
GSTexture* new_t = FetchSurface(type, w, h, levels, fmt, clear, prefer_reuse);
|
||||
if (new_t)
|
||||
{
|
||||
if (t2)
|
||||
{
|
||||
// TODO: We probably want to make this optional if we're overwriting it...
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0, 0, t2->GetWidth(), t2->GetHeight());
|
||||
StretchRect(t2, sRect, new_t, dRect, ShaderConvert::COPY, true);
|
||||
Recycle(t2);
|
||||
}
|
||||
|
||||
t2 = new_t;
|
||||
*t = t2;
|
||||
}
|
||||
constexpr GSVector4 sRect = GSVector4::cxpr(0, 0, 1, 1);
|
||||
const GSVector4 dRect = GSVector4(orig_tex->GetRect());
|
||||
StretchRect(orig_tex, sRect, new_tex, dRect, ShaderConvert::COPY, true);
|
||||
}
|
||||
|
||||
return t2 != NULL;
|
||||
}
|
||||
if (orig_tex)
|
||||
{
|
||||
if (recycle)
|
||||
Recycle(orig_tex);
|
||||
else
|
||||
delete orig_tex;
|
||||
}
|
||||
|
||||
bool GSDevice::ResizeTexture(GSTexture** t, int w, int h, bool prefer_reuse)
|
||||
{
|
||||
return ResizeTexture(t, GSTexture::Type::Texture, w, h, false, prefer_reuse);
|
||||
}
|
||||
|
||||
bool GSDevice::ResizeTarget(GSTexture** t, int w, int h)
|
||||
{
|
||||
return ResizeTexture(t, GSTexture::Type::RenderTarget, w, h);
|
||||
}
|
||||
|
||||
bool GSDevice::ResizeTarget(GSTexture** t)
|
||||
{
|
||||
GSVector2i s = m_current->GetSize();
|
||||
return ResizeTexture(t, GSTexture::Type::RenderTarget, s.x, s.y);
|
||||
*t = new_tex;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSDevice::SetHWDrawConfigForAlphaPass(GSHWDrawConfig::PSSelector* ps,
|
||||
|
||||
@@ -627,7 +627,7 @@ struct alignas(16) GSHWDrawConfig
|
||||
GSTexture* tex; ///< Source texture
|
||||
GSTexture* pal; ///< Palette texture
|
||||
const GSVertex* verts;///< Vertices to draw
|
||||
const u32* indices; ///< Indices to draw
|
||||
const u16* indices; ///< Indices to draw
|
||||
u32 nverts; ///< Number of vertices
|
||||
u32 nindices; ///< Number of indices
|
||||
u32 indices_per_prim; ///< Number of indices that make up one primitive
|
||||
@@ -738,18 +738,21 @@ public:
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
FastList<GSTexture*> m_pool;
|
||||
std::array<FastList<GSTexture*>, 2> m_pool; // [texture, target]
|
||||
u64 m_pool_memory_usage = 0;
|
||||
|
||||
static const std::array<HWBlend, 3*3*3*3> m_blendMap;
|
||||
static const std::array<u8, 16> m_replaceDualSrcBlendMap;
|
||||
|
||||
protected:
|
||||
static constexpr int NUM_INTERLACE_SHADERS = 5;
|
||||
static constexpr int NUM_INTERLACE_SHADERS = 5;
|
||||
static constexpr float MAD_SENSITIVITY = 0.08f;
|
||||
static constexpr u32 MAX_POOLED_TEXTURES = 300;
|
||||
static constexpr u32 NUM_CAS_CONSTANTS = 12; // 8 plus src offset x/y, 16 byte alignment
|
||||
static constexpr u32 EXPAND_BUFFER_SIZE = sizeof(u32) * std::numeric_limits<u16>::max() * 6;
|
||||
static constexpr u32 MAX_POOLED_TARGETS = 300;
|
||||
static constexpr u32 MAX_TARGET_AGE = 20;
|
||||
static constexpr u32 MAX_POOLED_TEXTURES = 300;
|
||||
static constexpr u32 MAX_TEXTURE_AGE = 10;
|
||||
static constexpr u32 NUM_CAS_CONSTANTS = 12; // 8 plus src offset x/y, 16 byte alignment
|
||||
static constexpr u32 EXPAND_BUFFER_SIZE = sizeof(u16) * 65532 * 6;
|
||||
|
||||
WindowInfo m_window_info;
|
||||
VsyncMode m_vsync_mode = VsyncMode::Off;
|
||||
@@ -806,7 +809,6 @@ public:
|
||||
/// Generates a fixed index buffer for expanding points and sprites. Buffer is assumed to be at least EXPAND_BUFFER_SIZE in size.
|
||||
static void GenerateExpansionIndexBuffer(void* buffer);
|
||||
|
||||
__fi unsigned int GetFrameNumber() const { return m_frame; }
|
||||
__fi u64 GetPoolMemoryUsage() const { return m_pool_memory_usage; }
|
||||
|
||||
__fi FeatureSupport Features() const { return m_features; }
|
||||
@@ -890,7 +892,6 @@ public:
|
||||
GSTexture* CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear = true);
|
||||
GSTexture* CreateDepthStencil(int w, int h, GSTexture::Format format, bool clear = true);
|
||||
GSTexture* CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
|
||||
GSTexture::Format GetDefaultTextureFormat(GSTexture::Type type);
|
||||
|
||||
virtual std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) = 0;
|
||||
|
||||
@@ -929,10 +930,7 @@ public:
|
||||
|
||||
void CAS(GSTexture*& tex, GSVector4i& src_rect, GSVector4& src_uv, const GSVector4& draw_rect, bool sharpen_only);
|
||||
|
||||
bool ResizeTexture(GSTexture** t, GSTexture::Type type, int w, int h, bool clear = true, bool prefer_reuse = false);
|
||||
bool ResizeTexture(GSTexture** t, int w, int h, bool prefer_reuse = false);
|
||||
bool ResizeTarget(GSTexture** t, int w, int h);
|
||||
bool ResizeTarget(GSTexture** t);
|
||||
bool ResizeRenderTarget(GSTexture** t, int w, int h, bool preserve_contents, bool recycle);
|
||||
|
||||
bool IsRBSwapped() { return m_rbswapped; }
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ void GSRenderer::EndPresentFrame()
|
||||
ImGuiManager::NewFrame();
|
||||
}
|
||||
|
||||
void GSRenderer::VSync(u32 field, bool registers_written)
|
||||
void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
{
|
||||
Flush(GSFlushReason::VSYNC);
|
||||
|
||||
@@ -569,6 +569,9 @@ void GSRenderer::VSync(u32 field, bool registers_written)
|
||||
|
||||
const bool blank_frame = !Merge(field);
|
||||
|
||||
m_last_draw_n = s_n;
|
||||
m_last_transfer_n = s_transfer_n;
|
||||
|
||||
if (skip_frame)
|
||||
{
|
||||
if (BeginPresentFrame(true))
|
||||
@@ -578,7 +581,8 @@ void GSRenderer::VSync(u32 field, bool registers_written)
|
||||
return;
|
||||
}
|
||||
|
||||
g_gs_device->AgePool();
|
||||
if (!idle_frame)
|
||||
g_gs_device->AgePool();
|
||||
|
||||
g_perfmon.EndFrame();
|
||||
if ((g_perfmon.GetFrame() & 0x1f) == 0)
|
||||
@@ -898,6 +902,11 @@ GSTexture* GSRenderer::LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool GSRenderer::IsIdleFrame() const
|
||||
{
|
||||
return (m_last_draw_n == s_n && m_last_transfer_n == s_transfer_n);
|
||||
}
|
||||
|
||||
bool GSRenderer::SaveSnapshotToMemory(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders,
|
||||
u32* width, u32* height, std::vector<u32>* pixels)
|
||||
{
|
||||
|
||||
@@ -32,6 +32,10 @@ private:
|
||||
u32 m_dump_frames = 0;
|
||||
u32 m_skipped_duplicate_frames = 0;
|
||||
|
||||
// Tracking draw counters for idle frame detection.
|
||||
int m_last_draw_n = 0;
|
||||
int m_last_transfer_n = 0;
|
||||
|
||||
protected:
|
||||
GSVector2i m_real_size{0, 0};
|
||||
bool m_texture_shuffle = false;
|
||||
@@ -48,7 +52,7 @@ public:
|
||||
|
||||
virtual void Destroy();
|
||||
|
||||
virtual void VSync(u32 field, bool registers_written);
|
||||
virtual void VSync(u32 field, bool registers_written, bool idle_frame);
|
||||
virtual bool CanUpscale() { return false; }
|
||||
virtual float GetUpscaleMultiplier() { return 1.0f; }
|
||||
virtual float GetTextureScaleFactor() { return 1.0f; }
|
||||
@@ -57,6 +61,8 @@ public:
|
||||
|
||||
virtual GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size);
|
||||
|
||||
bool IsIdleFrame() const;
|
||||
|
||||
bool SaveSnapshotToMemory(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders,
|
||||
u32* width, u32* height, std::vector<u32>* pixels);
|
||||
|
||||
|
||||
@@ -126,6 +126,10 @@ public:
|
||||
{
|
||||
return (m_type == Type::DepthStencil);
|
||||
}
|
||||
__fi bool IsTexture() const
|
||||
{
|
||||
return (m_type == Type::Texture);
|
||||
}
|
||||
|
||||
__fi State GetState() const { return m_state; }
|
||||
__fi void SetState(State state) { m_state = state; }
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSVertexList.h"
|
||||
@@ -1,82 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
template <class Vertex>
|
||||
class GSVertexList
|
||||
{
|
||||
void* m_base;
|
||||
Vertex* m_v[3];
|
||||
int m_count;
|
||||
|
||||
public:
|
||||
GSVertexList()
|
||||
: m_count(0)
|
||||
{
|
||||
m_base = _aligned_malloc(sizeof(Vertex) * std::size(m_v), 32);
|
||||
|
||||
for (size_t i = 0; i < std::size(m_v); i++)
|
||||
{
|
||||
m_v[i] = &((Vertex*)m_base)[i];
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~GSVertexList()
|
||||
{
|
||||
_aligned_free(m_base);
|
||||
}
|
||||
|
||||
void RemoveAll()
|
||||
{
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
__forceinline Vertex& AddTail()
|
||||
{
|
||||
ASSERT(m_count < 3);
|
||||
|
||||
return *m_v[m_count++];
|
||||
}
|
||||
|
||||
__forceinline void RemoveAt(int pos, int keep)
|
||||
{
|
||||
if (keep == 1)
|
||||
{
|
||||
Vertex* tmp = m_v[pos + 0];
|
||||
m_v[pos + 0] = m_v[pos + 1];
|
||||
m_v[pos + 1] = tmp;
|
||||
}
|
||||
else if (keep == 2)
|
||||
{
|
||||
Vertex* tmp = m_v[pos + 0];
|
||||
m_v[pos + 0] = m_v[pos + 1];
|
||||
m_v[pos + 1] = m_v[pos + 2];
|
||||
m_v[pos + 2] = tmp;
|
||||
}
|
||||
|
||||
m_count = pos + keep;
|
||||
}
|
||||
|
||||
__forceinline void GetAt(int i, Vertex& v)
|
||||
{
|
||||
v = *m_v[i];
|
||||
}
|
||||
|
||||
int GetCount()
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
};
|
||||
@@ -24,7 +24,7 @@ GSVertexTrace::GSVertexTrace(const GSState* state, bool provoking_vertex_first)
|
||||
MULTI_ISA_SELECT(GSVertexTracePopulateFunctions)(*this, provoking_vertex_first);
|
||||
}
|
||||
|
||||
void GSVertexTrace::Update(const void* vertex, const u32* index, int v_count, int i_count, GS_PRIM_CLASS primclass)
|
||||
void GSVertexTrace::Update(const void* vertex, const u16* index, int v_count, int i_count, GS_PRIM_CLASS primclass)
|
||||
{
|
||||
if (i_count == 0)
|
||||
return;
|
||||
@@ -43,7 +43,7 @@ void GSVertexTrace::Update(const void* vertex, const u32* index, int v_count, in
|
||||
// that feel big enough.
|
||||
if (!fst && !m_accurate_stq && m_min.t.z > 1e30)
|
||||
{
|
||||
fprintf(stderr, "Vertex Trace: float overflow detected ! min %e max %e\n", m_min.t.z, m_max.t.z);
|
||||
Console.Warning("Vertex Trace: float overflow detected ! min %e max %e", m_min.t.z, m_max.t.z);
|
||||
m_accurate_stq = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
protected:
|
||||
const GSState* m_state;
|
||||
|
||||
typedef void (*FindMinMaxPtr)(GSVertexTrace& vt, const void* vertex, const u32* index, int count);
|
||||
typedef void (*FindMinMaxPtr)(GSVertexTrace& vt, const void* vertex, const u16* index, int count);
|
||||
|
||||
FindMinMaxPtr m_fmm[2][2][2][2][4];
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
public:
|
||||
GSVertexTrace(const GSState* state, bool provoking_vertex_first);
|
||||
|
||||
void Update(const void* vertex, const u32* index, int v_count, int i_count, GS_PRIM_CLASS primclass);
|
||||
void Update(const void* vertex, const u16* index, int v_count, int i_count, GS_PRIM_CLASS primclass);
|
||||
|
||||
bool IsLinear() const { return m_filter.opt_linear; }
|
||||
bool IsRealLinear() const { return m_filter.linear; }
|
||||
|
||||
@@ -22,7 +22,7 @@ class CURRENT_ISA::GSVertexTraceFMM
|
||||
static constexpr GSVector4 s_minmax = GSVector4::cxpr(FLT_MAX, -FLT_MAX, 0.f, 0.f);
|
||||
|
||||
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color, bool flat_swapped>
|
||||
static void FindMinMax(GSVertexTrace& vt, const void* vertex, const u32* index, int count);
|
||||
static void FindMinMax(GSVertexTrace& vt, const void* vertex, const u16* index, int count);
|
||||
|
||||
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
|
||||
static constexpr GSVertexTrace::FindMinMaxPtr GetFMM(bool provoking_vertex_first);
|
||||
@@ -76,7 +76,7 @@ void GSVertexTraceFMM::Populate(GSVertexTrace& vt, bool provoking_vertex_first)
|
||||
}
|
||||
|
||||
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color, bool flat_swapped>
|
||||
void GSVertexTraceFMM::FindMinMax(GSVertexTrace& vt, const void* vertex, const u32* index, int count)
|
||||
void GSVertexTraceFMM::FindMinMax(GSVertexTrace& vt, const void* vertex, const u16* index, int count)
|
||||
{
|
||||
const GSDrawingContext* context = vt.m_state->m_context;
|
||||
|
||||
|
||||
@@ -883,7 +883,9 @@ GSDevice::PresentResult GSDevice11::BeginPresent(bool frame_skip)
|
||||
{
|
||||
m_state.dsv->Release();
|
||||
m_state.dsv = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, 1);
|
||||
|
||||
const GSVector2i size = GetWindowSize();
|
||||
SetViewport(size);
|
||||
@@ -1440,7 +1442,7 @@ void GSDevice11::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rect
|
||||
const u32 vertex_reserve_size = num_rects * 4;
|
||||
const u32 index_reserve_size = num_rects * 6;
|
||||
GSVertexPT1* verts = static_cast<GSVertexPT1*>(IAMapVertexBuffer(sizeof(GSVertexPT1), vertex_reserve_size));
|
||||
u32* idx = IAMapIndexBuffer(index_reserve_size);
|
||||
u16* idx = IAMapIndexBuffer(index_reserve_size);
|
||||
u32 icount = 0;
|
||||
u32 vcount = 0;
|
||||
for (u32 i = 0; i < num_rects; i++)
|
||||
@@ -1712,7 +1714,6 @@ void GSDevice11::RenderImGui()
|
||||
const UINT vb_stride = sizeof(ImDrawVert);
|
||||
const UINT vb_offset = 0;
|
||||
m_ctx->IASetVertexBuffers(0, 1, m_vb.addressof(), &vb_stride, &vb_offset);
|
||||
m_ctx->IASetIndexBuffer(m_ib.get(), DXGI_FORMAT_R16_UINT, 0);
|
||||
IASetInputLayout(m_imgui.il.get());
|
||||
IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
VSSetShader(m_imgui.vs.get(), m_imgui.vs_cb.get());
|
||||
@@ -1756,16 +1757,8 @@ void GSDevice11::RenderImGui()
|
||||
m_ctx->Unmap(m_vb.get(), 0);
|
||||
}
|
||||
|
||||
// Bit awkward, because this is using 16-bit indices, not 32-bit.
|
||||
static_assert(sizeof(ImDrawIdx) == sizeof(u16));
|
||||
const u32 index_count = static_cast<u32>(cmd_list->IdxBuffer.Size + 1) / 2;
|
||||
u32* index_map = IAMapIndexBuffer(index_count);
|
||||
if (!index_map)
|
||||
continue;
|
||||
|
||||
const u32 index_start = m_index.start * 2;
|
||||
std::memcpy(index_map, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
IAUnmapIndexBuffer(index_count);
|
||||
IASetIndexBuffer(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size);
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
@@ -1787,14 +1780,13 @@ void GSDevice11::RenderImGui()
|
||||
m_state.ps_sr_views[0] = static_cast<ID3D11ShaderResourceView*>(pcmd->GetTexID());
|
||||
PSUpdateShaderState();
|
||||
|
||||
m_ctx->DrawIndexed(pcmd->ElemCount, index_start + pcmd->IdxOffset, vertex_offset + pcmd->VtxOffset);
|
||||
m_ctx->DrawIndexed(pcmd->ElemCount, m_index.start + pcmd->IdxOffset, vertex_offset + pcmd->VtxOffset);
|
||||
}
|
||||
|
||||
g_perfmon.Put(GSPerfMon::DrawCalls, cmd_list->CmdBuffer.Size);
|
||||
}
|
||||
|
||||
m_ctx->IASetVertexBuffers(0, 1, m_vb.addressof(), &m_state.vb_stride, &vb_offset);
|
||||
m_ctx->IASetIndexBuffer(m_state.index_buffer, DXGI_FORMAT_R32_UINT, 0);
|
||||
}
|
||||
|
||||
void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm)
|
||||
@@ -1912,9 +1904,9 @@ bool GSDevice11::IASetExpandVertexBuffer(const void* vertex, u32 stride, u32 cou
|
||||
return true;
|
||||
}
|
||||
|
||||
u32* GSDevice11::IAMapIndexBuffer(u32 count)
|
||||
u16* GSDevice11::IAMapIndexBuffer(u32 count)
|
||||
{
|
||||
if (count > (INDEX_BUFFER_SIZE / sizeof(u32)))
|
||||
if (count > (INDEX_BUFFER_SIZE / sizeof(u16)))
|
||||
return nullptr;
|
||||
|
||||
D3D11_MAP type = D3D11_MAP_WRITE_NO_OVERWRITE;
|
||||
@@ -1922,7 +1914,7 @@ u32* GSDevice11::IAMapIndexBuffer(u32 count)
|
||||
m_index.start = m_ib_pos;
|
||||
m_ib_pos += count;
|
||||
|
||||
if (m_ib_pos > (INDEX_BUFFER_SIZE / sizeof(u32)))
|
||||
if (m_ib_pos > (INDEX_BUFFER_SIZE / sizeof(u16)))
|
||||
{
|
||||
m_index.start = 0;
|
||||
m_ib_pos = count;
|
||||
@@ -1933,7 +1925,7 @@ u32* GSDevice11::IAMapIndexBuffer(u32 count)
|
||||
if (FAILED(m_ctx->Map(m_ib.get(), 0, type, 0, &m)))
|
||||
return nullptr;
|
||||
|
||||
return static_cast<u32*>(m.pData) + m_index.start;
|
||||
return static_cast<u16*>(m.pData) + m_index.start;
|
||||
}
|
||||
|
||||
void GSDevice11::IAUnmapIndexBuffer(u32 count)
|
||||
@@ -1944,11 +1936,11 @@ void GSDevice11::IAUnmapIndexBuffer(u32 count)
|
||||
|
||||
bool GSDevice11::IASetIndexBuffer(const void* index, u32 count)
|
||||
{
|
||||
u32* map = IAMapIndexBuffer(count);
|
||||
u16* map = IAMapIndexBuffer(count);
|
||||
if (!map)
|
||||
return false;
|
||||
|
||||
std::memcpy(map, index, count * sizeof(u32));
|
||||
std::memcpy(map, index, count * sizeof(u16));
|
||||
IAUnmapIndexBuffer(count);
|
||||
IASetIndexBuffer(m_ib.get());
|
||||
return true;
|
||||
@@ -1958,7 +1950,7 @@ void GSDevice11::IASetIndexBuffer(ID3D11Buffer* buffer)
|
||||
{
|
||||
if (m_state.index_buffer != buffer)
|
||||
{
|
||||
m_ctx->IASetIndexBuffer(buffer, DXGI_FORMAT_R32_UINT, 0);
|
||||
m_ctx->IASetIndexBuffer(buffer, DXGI_FORMAT_R16_UINT, 0);
|
||||
m_state.index_buffer = buffer;
|
||||
}
|
||||
}
|
||||
@@ -2073,6 +2065,8 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector
|
||||
if (ds) dsv = *(GSTexture11*)ds;
|
||||
|
||||
const bool changed = (m_state.rt_view != rtv || m_state.dsv != dsv);
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(changed));
|
||||
|
||||
if (m_state.rt_view != rtv)
|
||||
{
|
||||
if (m_state.rt_view)
|
||||
|
||||
@@ -343,7 +343,7 @@ public:
|
||||
bool IASetVertexBuffer(const void* vertex, u32 stride, u32 count);
|
||||
bool IASetExpandVertexBuffer(const void* vertex, u32 stride, u32 count);
|
||||
|
||||
u32* IAMapIndexBuffer(u32 count);
|
||||
u16* IAMapIndexBuffer(u32 count);
|
||||
void IAUnmapIndexBuffer(u32 count);
|
||||
bool IASetIndexBuffer(const void* index, u32 count);
|
||||
void IASetIndexBuffer(ID3D11Buffer* buffer);
|
||||
|
||||
@@ -538,6 +538,7 @@ GSDevice::PresentResult GSDevice12::BeginPresent(bool frame_skip)
|
||||
swap_chain_buf.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
cmdlist->ClearRenderTargetView(swap_chain_buf.GetWriteDescriptor(), clear_color.data(), 0, nullptr);
|
||||
cmdlist->OMSetRenderTargets(1, &swap_chain_buf.GetWriteDescriptor().cpu_handle, FALSE, nullptr);
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, 1);
|
||||
|
||||
const D3D12_VIEWPORT vp{0.0f, 0.0f, static_cast<float>(m_window_info.surface_width),
|
||||
static_cast<float>(m_window_info.surface_height), 0.0f, 1.0f};
|
||||
@@ -949,13 +950,13 @@ void GSDevice12::DoMultiStretchRects(
|
||||
{
|
||||
// Set up vertices first.
|
||||
const u32 vertex_reserve_size = num_rects * 4 * sizeof(GSVertexPT1);
|
||||
const u32 index_reserve_size = num_rects * 6 * sizeof(u32);
|
||||
const u32 index_reserve_size = num_rects * 6 * sizeof(u16);
|
||||
if (!m_vertex_stream_buffer.ReserveMemory(vertex_reserve_size, sizeof(GSVertexPT1)) ||
|
||||
!m_index_stream_buffer.ReserveMemory(index_reserve_size, sizeof(u32)))
|
||||
!m_index_stream_buffer.ReserveMemory(index_reserve_size, sizeof(u16)))
|
||||
{
|
||||
ExecuteCommandListAndRestartRenderPass(false, "Uploading bytes to vertex buffer");
|
||||
if (!m_vertex_stream_buffer.ReserveMemory(vertex_reserve_size, sizeof(GSVertexPT1)) ||
|
||||
!m_index_stream_buffer.ReserveMemory(index_reserve_size, sizeof(u32)))
|
||||
!m_index_stream_buffer.ReserveMemory(index_reserve_size, sizeof(u16)))
|
||||
{
|
||||
pxFailRel("Failed to reserve space for vertices");
|
||||
}
|
||||
@@ -965,7 +966,7 @@ void GSDevice12::DoMultiStretchRects(
|
||||
// Don't use primitive restart here, it ends up slower on some drivers.
|
||||
const GSVector2 ds(static_cast<float>(dTex->GetWidth()), static_cast<float>(dTex->GetHeight()));
|
||||
GSVertexPT1* verts = reinterpret_cast<GSVertexPT1*>(m_vertex_stream_buffer.GetCurrentHostPointer());
|
||||
u32* idx = reinterpret_cast<u32*>(m_index_stream_buffer.GetCurrentHostPointer());
|
||||
u16* idx = reinterpret_cast<u16*>(m_index_stream_buffer.GetCurrentHostPointer());
|
||||
u32 icount = 0;
|
||||
u32 vcount = 0;
|
||||
for (u32 i = 0; i < num_rects; i++)
|
||||
@@ -996,12 +997,12 @@ void GSDevice12::DoMultiStretchRects(
|
||||
|
||||
m_vertex.start = m_vertex_stream_buffer.GetCurrentOffset() / sizeof(GSVertexPT1);
|
||||
m_vertex.count = vcount;
|
||||
m_index.start = m_index_stream_buffer.GetCurrentOffset() / sizeof(u32);
|
||||
m_index.start = m_index_stream_buffer.GetCurrentOffset() / sizeof(u16);
|
||||
m_index.count = icount;
|
||||
m_vertex_stream_buffer.CommitMemory(vcount * sizeof(GSVertexPT1));
|
||||
m_index_stream_buffer.CommitMemory(icount * sizeof(u32));
|
||||
m_index_stream_buffer.CommitMemory(icount * sizeof(u16));
|
||||
SetVertexBuffer(m_vertex_stream_buffer.GetGPUPointer(), m_vertex_stream_buffer.GetSize(), sizeof(GSVertexPT1));
|
||||
SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(), m_index_stream_buffer.GetSize(), DXGI_FORMAT_R32_UINT);
|
||||
SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(), m_index_stream_buffer.GetSize(), DXGI_FORMAT_R16_UINT);
|
||||
|
||||
// Even though we're batching, a cmdbuffer submit could've messed this up.
|
||||
const GSVector4i rc(dTex->GetRect());
|
||||
@@ -1422,22 +1423,10 @@ void GSDevice12::RenderImGui()
|
||||
m_vertex_stream_buffer.CommitMemory(size);
|
||||
}
|
||||
|
||||
u32 index_offset;
|
||||
{
|
||||
const u32 size = sizeof(ImDrawIdx) * static_cast<u32>(cmd_list->IdxBuffer.Size);
|
||||
if (!m_index_stream_buffer.ReserveMemory(size, sizeof(ImDrawIdx)))
|
||||
{
|
||||
Console.Warning("Skipping ImGui draw because of no vertex buffer space");
|
||||
return;
|
||||
}
|
||||
|
||||
index_offset = m_index_stream_buffer.GetCurrentOffset() / sizeof(ImDrawIdx);
|
||||
std::memcpy(m_index_stream_buffer.GetCurrentHostPointer(), cmd_list->IdxBuffer.Data, size);
|
||||
m_index_stream_buffer.CommitMemory(size);
|
||||
}
|
||||
|
||||
SetVertexBuffer(m_vertex_stream_buffer.GetGPUPointer(), m_vertex_stream_buffer.GetSize(), sizeof(ImDrawVert));
|
||||
SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(), m_index_stream_buffer.GetSize(), DXGI_FORMAT_R16_UINT);
|
||||
|
||||
static_assert(sizeof(ImDrawIdx) == sizeof(u16));
|
||||
IASetIndexBuffer(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size);
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
@@ -1468,7 +1457,7 @@ void GSDevice12::RenderImGui()
|
||||
if (ApplyUtilityState())
|
||||
{
|
||||
g_d3d12_context->GetCommandList()->DrawIndexedInstanced(
|
||||
pcmd->ElemCount, 1, index_offset + pcmd->IdxOffset, vertex_offset + pcmd->VtxOffset, 0);
|
||||
pcmd->ElemCount, 1, m_index.start + pcmd->IdxOffset, vertex_offset + pcmd->VtxOffset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1536,17 +1525,17 @@ void GSDevice12::IASetVertexBuffer(const void* vertex, size_t stride, size_t cou
|
||||
|
||||
void GSDevice12::IASetIndexBuffer(const void* index, size_t count)
|
||||
{
|
||||
const u32 size = sizeof(u32) * static_cast<u32>(count);
|
||||
if (!m_index_stream_buffer.ReserveMemory(size, sizeof(u32)))
|
||||
const u32 size = sizeof(u16) * static_cast<u32>(count);
|
||||
if (!m_index_stream_buffer.ReserveMemory(size, sizeof(u16)))
|
||||
{
|
||||
ExecuteCommandListAndRestartRenderPass(false, "Uploading bytes to index buffer");
|
||||
if (!m_index_stream_buffer.ReserveMemory(size, sizeof(u32)))
|
||||
if (!m_index_stream_buffer.ReserveMemory(size, sizeof(u16)))
|
||||
pxFailRel("Failed to reserve space for vertices");
|
||||
}
|
||||
|
||||
m_index.start = m_index_stream_buffer.GetCurrentOffset() / sizeof(u32);
|
||||
m_index.start = m_index_stream_buffer.GetCurrentOffset() / sizeof(u16);
|
||||
m_index.count = count;
|
||||
SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(), m_index_stream_buffer.GetSize(), DXGI_FORMAT_R32_UINT);
|
||||
SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(), m_index_stream_buffer.GetSize(), DXGI_FORMAT_R16_UINT);
|
||||
|
||||
std::memcpy(m_index_stream_buffer.GetCurrentHostPointer(), index, size);
|
||||
m_index_stream_buffer.CommitMemory(size);
|
||||
@@ -2758,11 +2747,15 @@ void GSDevice12::EndRenderPass()
|
||||
if (!m_in_render_pass)
|
||||
return;
|
||||
|
||||
g_d3d12_context->GetCommandList()->EndRenderPass();
|
||||
m_in_render_pass = false;
|
||||
|
||||
// to render again, we need to reset OM
|
||||
m_dirty_flags |= DIRTY_FLAG_RENDER_TARGET;
|
||||
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, 1);
|
||||
|
||||
g_d3d12_context->GetCommandList()->EndRenderPass();
|
||||
|
||||
}
|
||||
|
||||
void GSDevice12::SetViewport(const D3D12_VIEWPORT& viewport)
|
||||
@@ -3212,8 +3205,20 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
|
||||
// avoid restarting the render pass just to switch from rt+depth to rt and vice versa
|
||||
if (m_in_render_pass && !hdr_rt && !draw_ds && m_current_depth_target && m_current_render_target == draw_rt &&
|
||||
config.tex != m_current_depth_target && m_current_depth_target->GetSize() == draw_rt->GetSize())
|
||||
if (m_in_render_pass && (m_current_render_target == draw_rt || m_current_depth_target == draw_ds))
|
||||
{
|
||||
// avoid restarting the render pass just to switch from rt+depth to rt and vice versa
|
||||
// keep the depth even if doing HDR draws, because the next draw will probably re-enable depth
|
||||
if (!draw_rt && m_current_render_target && config.tex != m_current_render_target &&
|
||||
m_current_render_target->GetSize() == draw_ds->GetSize())
|
||||
{
|
||||
draw_rt = m_current_render_target;
|
||||
m_pipeline_selector.rt = true;
|
||||
m_pipeline_selector.cms.wrgba = 0;
|
||||
}
|
||||
}
|
||||
else if (!draw_ds && m_current_depth_target && config.tex != m_current_depth_target &&
|
||||
m_current_depth_target->GetSize() == draw_rt->GetSize())
|
||||
{
|
||||
draw_ds = m_current_depth_target;
|
||||
m_pipeline_selector.ds = true;
|
||||
@@ -3353,7 +3358,7 @@ void GSDevice12::UploadHWDrawVerticesAndIndices(const GSHWDrawConfig& config)
|
||||
{
|
||||
m_index.start = 0;
|
||||
m_index.count = config.nindices;
|
||||
SetIndexBuffer(m_expand_index_buffer->GetGPUVirtualAddress(), EXPAND_BUFFER_SIZE, DXGI_FORMAT_R32_UINT);
|
||||
SetIndexBuffer(m_expand_index_buffer->GetGPUVirtualAddress(), EXPAND_BUFFER_SIZE, DXGI_FORMAT_R16_UINT);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -297,7 +297,7 @@ bool GSHwHack::GSC_BlackAndBurnoutSky(GSRendererHW& r, int& skip)
|
||||
if (RPRIM->PRIM == GS_SPRITE && !RPRIM->IIP && RPRIM->TME && !RPRIM->FGE && RPRIM->ABE && !RPRIM->AA1 && !RPRIM->FST && !RPRIM->FIX &&
|
||||
ALPHA.A == ALPHA.B && ALPHA.D == 0 && FRAME.PSM == PSMCT32 && TEX0.CPSM == PSMCT32 && TEX0.TCC && !TEX0.TFX && !TEX0.CSM)
|
||||
{
|
||||
if (TEX0.TBW == 16 && TEX0.TW == 10 && TEX0.PSM == PSMT8 && TEX0.TH == 8 && FRAME.FBW == 16)
|
||||
if (TEX0.TBW == 16 && TEX0.TW == 10 && TEX0.PSM == PSMT8 && TEX0.TH >= 7 && FRAME.FBW == 16)
|
||||
{
|
||||
// Readback clouds being rendered during level loading.
|
||||
// Later the alpha channel from the 32 bit frame buffer is used as an 8 bit indexed texture to draw
|
||||
|
||||
@@ -112,7 +112,7 @@ void GSRendererHW::UpdateSettings(const Pcsx2Config::GSOptions& old_config)
|
||||
SetTCOffset();
|
||||
}
|
||||
|
||||
void GSRendererHW::VSync(u32 field, bool registers_written)
|
||||
void GSRendererHW::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
{
|
||||
if (m_force_preload > 0)
|
||||
{
|
||||
@@ -138,7 +138,7 @@ void GSRendererHW::VSync(u32 field, bool registers_written)
|
||||
|
||||
// Don't age the texture cache when no draws or EE writes have occurred.
|
||||
// Xenosaga needs its targets kept around while it's loading, because it uses them for a fade transition.
|
||||
if (m_last_draw_n == s_n && m_last_transfer_n == s_transfer_n)
|
||||
if (idle_frame)
|
||||
{
|
||||
GL_INS("No draws or transfers, not aging TC");
|
||||
}
|
||||
@@ -147,10 +147,7 @@ void GSRendererHW::VSync(u32 field, bool registers_written)
|
||||
g_texture_cache->IncAge();
|
||||
}
|
||||
|
||||
m_last_draw_n = s_n + 1; // +1 for vsync
|
||||
m_last_transfer_n = s_transfer_n;
|
||||
|
||||
GSRenderer::VSync(field, registers_written);
|
||||
GSRenderer::VSync(field, registers_written, idle_frame);
|
||||
|
||||
if (g_texture_cache->GetHashCacheMemoryUsage() > 1024 * 1024 * 1024)
|
||||
{
|
||||
@@ -258,14 +255,10 @@ void GSRendererHW::Lines2Sprites()
|
||||
int i = static_cast<int>(count) * 2 - 4;
|
||||
GSVertex* s = &m_vertex.buff[count - 2];
|
||||
GSVertex* q = &m_vertex.buff[count * 2 - 4];
|
||||
u32* RESTRICT index = &m_index.buff[count * 3 - 6];
|
||||
u16* RESTRICT index = &m_index.buff[count * 3 - 6];
|
||||
|
||||
alignas(16) static constexpr std::array<int, 8> tri_normal_indices = {{0, 1, 2, 1, 2, 3}};
|
||||
alignas(16) static constexpr std::array<int, 8> tri_swapped_indices = {{0, 1, 2, 1, 2, 3}};
|
||||
const bool index_swap = !g_gs_device->Features().provoking_vertex_last;
|
||||
const int* tri_indices = index_swap ? tri_swapped_indices.data() : tri_normal_indices.data();
|
||||
const GSVector4i indices_low(GSVector4i::load<true>(tri_indices));
|
||||
const GSVector4i indices_high(GSVector4i::loadl(tri_indices + 4));
|
||||
// Sprites are flat shaded, so the provoking vertex doesn't matter here.
|
||||
constexpr GSVector4i indices = GSVector4i::cxpr16(0, 1, 2, 1, 2, 3, 0, 0);
|
||||
|
||||
for (; i >= 0; i -= 4, s -= 2, q -= 4, index -= 6)
|
||||
{
|
||||
@@ -310,9 +303,10 @@ void GSRendererHW::Lines2Sprites()
|
||||
q[1] = v0;
|
||||
q[2] = v1;
|
||||
|
||||
const GSVector4i i_splat(i);
|
||||
GSVector4i::store<false>(index, i_splat + indices_low);
|
||||
GSVector4i::storel(index + 4, i_splat + indices_high);
|
||||
const GSVector4i this_indices = GSVector4i::broadcast16(i).add16(indices);
|
||||
const int high = this_indices.extract32<2>();
|
||||
GSVector4i::storel(index, this_indices);
|
||||
std::memcpy(&index[4], &high, sizeof(high));
|
||||
}
|
||||
|
||||
m_vertex.head = m_vertex.tail = m_vertex.next = count * 2;
|
||||
@@ -322,26 +316,30 @@ void GSRendererHW::Lines2Sprites()
|
||||
|
||||
void GSRendererHW::ExpandLineIndices()
|
||||
{
|
||||
const u32 process_count = (m_index.tail + 3) / 4 * 4;
|
||||
const u32 process_count = (m_index.tail + 7) / 8 * 8;
|
||||
const u32 expansion_factor = 3;
|
||||
m_index.tail *= expansion_factor;
|
||||
GSVector4i* end = reinterpret_cast<GSVector4i*>(m_index.buff);
|
||||
GSVector4i* read = reinterpret_cast<GSVector4i*>(m_index.buff + process_count);
|
||||
GSVector4i* write = reinterpret_cast<GSVector4i*>(m_index.buff + process_count * expansion_factor);
|
||||
|
||||
constexpr GSVector4i low0 = GSVector4i::cxpr(0, 1, 2, 1);
|
||||
constexpr GSVector4i low1 = GSVector4i::cxpr(2, 3, 0, 1);
|
||||
constexpr GSVector4i low2 = GSVector4i::cxpr(2, 1, 2, 3);
|
||||
constexpr GSVector4i mask0 = GSVector4i::cxpr8(0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5);
|
||||
constexpr GSVector4i mask1 = GSVector4i::cxpr8(6, 7, 4, 5, 6, 7, 6, 7, 8, 9, 8, 9, 10, 11, 8, 9);
|
||||
constexpr GSVector4i mask2 = GSVector4i::cxpr8(10, 11, 10, 11, 12, 13, 12, 13, 14, 15, 12, 13, 14, 15, 14, 15);
|
||||
|
||||
constexpr GSVector4i low0 = GSVector4i::cxpr16(0, 1, 2, 1, 2, 3, 0, 1);
|
||||
constexpr GSVector4i low1 = GSVector4i::cxpr16(2, 1, 2, 3, 0, 1, 2, 1);
|
||||
constexpr GSVector4i low2 = GSVector4i::cxpr16(2, 3, 0, 1, 2, 1, 2, 3);
|
||||
|
||||
while (read > end)
|
||||
{
|
||||
read -= 1;
|
||||
write -= expansion_factor;
|
||||
|
||||
const GSVector4i in = read->sll32(2);
|
||||
write[0] = in.xxyx() | low0;
|
||||
write[1] = in.yyzz() | low1;
|
||||
write[2] = in.wzww() | low2;
|
||||
const GSVector4i in = read->sll16(2);
|
||||
write[0] = in.shuffle8(mask0) | low0;
|
||||
write[1] = in.shuffle8(mask1) | low1;
|
||||
write[2] = in.shuffle8(mask2) | low2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1434,7 +1432,7 @@ void GSRendererHW::Draw()
|
||||
#endif
|
||||
}
|
||||
|
||||
GL_PUSH("HW Draw %d", s_n);
|
||||
GL_PUSH("HW Draw %d (Context %u)", s_n, PRIM->CTXT);
|
||||
|
||||
// When the format is 24bit (Z or C), DATE ceases to function.
|
||||
// It was believed that in 24bit mode all pixels pass because alpha doesn't exist
|
||||
@@ -3606,11 +3604,11 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
const u8 wms = EffectiveClamp(m_cached_ctx.CLAMP.WMS, !tex->m_target && (source_region.HasX() || redundant_wms));
|
||||
const u8 wmt = EffectiveClamp(m_cached_ctx.CLAMP.WMT, !tex->m_target && (source_region.HasY() || redundant_wmt));
|
||||
const bool complex_wms_wmt = !!((wms | wmt) & 2) || target_region;
|
||||
GL_CACHE("WMS: %s [%s%s] WMT: %s [%s%s] Complex: %d TargetRegion: %d MINU: %d MAXU: %d MINV: %d MAXV: %d",
|
||||
clamp_modes[m_cached_ctx.CLAMP.WMS], redundant_wms ? "redundant," : "", clamp_modes[wms],
|
||||
clamp_modes[m_cached_ctx.CLAMP.WMT], redundant_wmt ? "redundant," : "", clamp_modes[wmt],
|
||||
complex_wms_wmt, target_region,
|
||||
m_cached_ctx.CLAMP.MINU, m_cached_ctx.CLAMP.MAXU, m_cached_ctx.CLAMP.MINV, m_cached_ctx.CLAMP.MAXV);
|
||||
GL_CACHE("FST: %s WMS: %s [%s%s] WMT: %s [%s%s] Complex: %d TargetRegion: %d MINU: %d MAXU: %d MINV: %d MAXV: %d",
|
||||
PRIM->FST ? "UV" : "STQ", clamp_modes[m_cached_ctx.CLAMP.WMS], redundant_wms ? "redundant," : "",
|
||||
clamp_modes[wms], clamp_modes[m_cached_ctx.CLAMP.WMT], redundant_wmt ? "redundant," : "", clamp_modes[wmt],
|
||||
complex_wms_wmt, target_region, m_cached_ctx.CLAMP.MINU, m_cached_ctx.CLAMP.MAXU, m_cached_ctx.CLAMP.MINV,
|
||||
m_cached_ctx.CLAMP.MAXV);
|
||||
|
||||
const bool need_mipmap = IsMipMapDraw();
|
||||
const bool shader_emulated_sampler = tex->m_palette || (tex->m_target && !m_conf.ps.shuffle && cpsm.fmt != 0) ||
|
||||
@@ -4934,16 +4932,15 @@ void GSRendererHW::OI_DoubleHalfClear(GSTextureCache::Target*& rt, GSTextureCach
|
||||
clear_depth ? "depth" : "target", base << 5, half << 5, w_pages, h_pages, m_cached_ctx.FRAME.FBW, color);
|
||||
|
||||
// If some of the channels are masked, we need to keep them.
|
||||
if (m_cached_ctx.FRAME.FBMSK != 0)
|
||||
if (!clear_depth && m_cached_ctx.FRAME.FBMSK != 0)
|
||||
{
|
||||
GSTexture* tex = nullptr;
|
||||
GSTextureCache::Target* target = clear_depth ? ds : rt;
|
||||
const GSVector2 size = GSVector2(static_cast<float>(target->GetUnscaledWidth()) * target->m_scale, static_cast<float>(target->GetUnscaledHeight()) * target->m_scale);
|
||||
pxAssert(!target->m_texture->IsDepthStencil());
|
||||
try
|
||||
{
|
||||
tex = target->m_texture->IsDepthStencil() ?
|
||||
g_gs_device->CreateDepthStencil(size.x, size.y, target->m_texture->GetFormat(), true) :
|
||||
g_gs_device->CreateRenderTarget(size.x, size.y, target->m_texture->GetFormat(), true);
|
||||
tex = g_gs_device->CreateRenderTarget(size.x, size.y, target->m_texture->GetFormat(), false);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
|
||||
@@ -149,10 +149,6 @@ private:
|
||||
std::unique_ptr<GSTextureCacheSW::Texture> m_sw_texture[7 + 1];
|
||||
std::unique_ptr<GSVirtualAlignedClass<32>> m_sw_rasterizer;
|
||||
|
||||
// Tracking draw counters for idle frame detection.
|
||||
int m_last_draw_n = 0;
|
||||
int m_last_transfer_n = 0;
|
||||
|
||||
public:
|
||||
GSRendererHW();
|
||||
virtual ~GSRendererHW() override;
|
||||
@@ -178,7 +174,7 @@ public:
|
||||
|
||||
void Reset(bool hardware_reset) override;
|
||||
void UpdateSettings(const Pcsx2Config::GSOptions& old_config) override;
|
||||
void VSync(u32 field, bool registers_written) override;
|
||||
void VSync(u32 field, bool registers_written, bool idle_frame) override;
|
||||
|
||||
GSTexture* GetOutput(int i, float& scale, int& y_offset) override;
|
||||
GSTexture* GetFeedbackOutput(float& scale) override;
|
||||
|
||||
@@ -35,12 +35,16 @@ std::unique_ptr<GSTextureCache> g_texture_cache;
|
||||
|
||||
static u8* s_unswizzle_buffer;
|
||||
|
||||
/// List of candidates for purging when the hash cache gets too large.
|
||||
static std::vector<std::pair<GSTextureCache::HashCacheMap::iterator, s32>> s_hash_cache_purge_list;
|
||||
|
||||
GSTextureCache::GSTextureCache()
|
||||
{
|
||||
// In theory 4MB is enough but 9MB is safer for overflow (8MB
|
||||
// isn't enough in custom resolution)
|
||||
// Test: onimusha 3 PAL 60Hz
|
||||
s_unswizzle_buffer = (u8*)_aligned_malloc(9 * 1024 * 1024, 32);
|
||||
s_unswizzle_buffer = (u8*)_aligned_malloc(9 * 1024 * 1024, VECTOR_ALIGNMENT);
|
||||
pxAssertRel(s_unswizzle_buffer, "Failed to allocate unswizzle buffer");
|
||||
|
||||
m_surface_offset_cache.reserve(S_SURFACE_OFFSET_CACHE_MAX_SIZE);
|
||||
}
|
||||
@@ -49,6 +53,7 @@ GSTextureCache::~GSTextureCache()
|
||||
{
|
||||
RemoveAll();
|
||||
|
||||
s_hash_cache_purge_list = {};
|
||||
_aligned_free(s_unswizzle_buffer);
|
||||
}
|
||||
|
||||
@@ -851,8 +856,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||
// If the source is reading the rt, make sure it's big enough.
|
||||
if (t && GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM))
|
||||
{
|
||||
GSVector4i dirty_rect = t->m_dirty.GetTotalRect(t->m_TEX0, GSVector2i(new_rect.z, new_rect.w));
|
||||
const GSVector2i size_delta = { (dirty_rect.z - t->m_valid.z), (dirty_rect.w - t->m_valid.w) };
|
||||
const GSVector2i size_delta = { (new_rect.z - t->m_valid.z), (new_rect.w - t->m_valid.w) };
|
||||
if (size_delta.x > 0 || size_delta.y > 0)
|
||||
{
|
||||
RGBAMask rgba;
|
||||
@@ -1267,7 +1271,13 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
g_gs_device->StretchRect(dst->m_texture, sRect, tex, dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
m_target_memory_usage = (m_target_memory_usage - dst->m_texture->GetMemUsage()) + tex->GetMemUsage();
|
||||
g_gs_device->Recycle(dst->m_texture);
|
||||
|
||||
// If we're changing resolution scale, just toss the texture, it's not going to get reused.
|
||||
if (!GSConfig.UserHacks_NativePaletteDraw || (dst->m_scale != 1.0f && scale != 1.0f))
|
||||
delete dst->m_texture;
|
||||
else
|
||||
g_gs_device->Recycle(dst->m_texture);
|
||||
|
||||
dst->m_texture = tex;
|
||||
dst->m_scale = scale;
|
||||
dst->m_unscaled_size = new_size;
|
||||
@@ -2576,7 +2586,7 @@ bool GSTextureCache::ShuffleMove(u32 BP, u32 BW, u32 PSM, int sx, int sy, int dx
|
||||
|
||||
#undef V
|
||||
|
||||
static constexpr u32 indices[6] = { 0, 1, 2, 2, 1, 3 };
|
||||
static constexpr u16 indices[6] = { 0, 1, 2, 2, 1, 3 };
|
||||
|
||||
// If we ever do this sort of thing somewhere else, extract this to a helper function.
|
||||
GSHWDrawConfig config;
|
||||
@@ -2832,29 +2842,11 @@ void GSTextureCache::IncAge()
|
||||
Source* s = *i;
|
||||
|
||||
++i;
|
||||
if (++s->m_age > (s->CanPreload() ? max_preload_age : max_age))
|
||||
if (++s->m_age > ((!s->m_from_hash_cache && s->CanPreload()) ? max_preload_age : max_age))
|
||||
m_src.RemoveAt(s);
|
||||
}
|
||||
|
||||
const u32 max_hash_cache_age = 30;
|
||||
for (auto it = m_hash_cache.begin(); it != m_hash_cache.end();)
|
||||
{
|
||||
HashCacheEntry& e = it->second;
|
||||
if (e.refcount == 0 && ++e.age > max_hash_cache_age)
|
||||
{
|
||||
const u32 mem_usage = e.texture->GetMemUsage();
|
||||
if (e.is_replacement)
|
||||
m_hash_cache_replacement_memory_usage -= mem_usage;
|
||||
else
|
||||
m_hash_cache_memory_usage -= mem_usage;
|
||||
g_gs_device->Recycle(e.texture);
|
||||
m_hash_cache.erase(it++);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
AgeHashCache();
|
||||
|
||||
// Clearing of Rendertargets causes flickering in many scene transitions.
|
||||
// Sigh, this seems to be used to invalidate surfaces. So set a huge maxage to avoid flicker,
|
||||
@@ -3605,6 +3597,7 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0
|
||||
if (it != m_hash_cache.end())
|
||||
{
|
||||
// super easy, cache hit. remove paltex if it's a replacement texture.
|
||||
GL_CACHE("HC Hit: %" PRIx64 " %" PRIx64 " R-%" PRIx64, key.TEX0Hash, key.CLUTHash, key.region.bits);
|
||||
HashCacheEntry* entry = &it->second;
|
||||
paltex &= (entry->texture->GetFormat() == GSTexture::Format::UNorm8);
|
||||
entry->refcount++;
|
||||
@@ -3612,6 +3605,8 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0
|
||||
}
|
||||
|
||||
// cache miss.
|
||||
GL_CACHE("HC Miss: %" PRIx64 " %" PRIx64 " R-%" PRIx64, key.TEX0Hash, key.CLUTHash, key.region.bits);
|
||||
|
||||
// check for a replacement texture with the full clut key
|
||||
if (replace)
|
||||
{
|
||||
@@ -3697,6 +3692,70 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0
|
||||
return &m_hash_cache.emplace(key, entry).first->second;
|
||||
}
|
||||
|
||||
void GSTextureCache::RemoveFromHashCache(HashCacheMap::iterator it)
|
||||
{
|
||||
HashCacheEntry& e = it->second;
|
||||
const u32 mem_usage = e.texture->GetMemUsage();
|
||||
if (e.is_replacement)
|
||||
m_hash_cache_replacement_memory_usage -= mem_usage;
|
||||
else
|
||||
m_hash_cache_memory_usage -= mem_usage;
|
||||
g_gs_device->Recycle(e.texture);
|
||||
m_hash_cache.erase(it);
|
||||
}
|
||||
|
||||
void GSTextureCache::AgeHashCache()
|
||||
{
|
||||
// Where did this number come from?
|
||||
// A game called Corvette draws its background FMVs with a ton of 17x17 tiles, which ends up
|
||||
// being about 600 texture uploads per frame. We'll use 800 as an upper bound for a bit of
|
||||
// a buffer, hopefully nothing's going to end up with more textures than that.
|
||||
constexpr u32 MAX_HASH_CACHE_SIZE = 800;
|
||||
constexpr u32 MAX_HASH_CACHE_AGE = 30;
|
||||
|
||||
bool might_need_cache_purge = (m_hash_cache.size() > MAX_HASH_CACHE_SIZE);
|
||||
if (might_need_cache_purge)
|
||||
s_hash_cache_purge_list.clear();
|
||||
|
||||
for (auto it = m_hash_cache.begin(); it != m_hash_cache.end();)
|
||||
{
|
||||
HashCacheEntry& e = it->second;
|
||||
if (e.refcount > 0)
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (++e.age > MAX_HASH_CACHE_AGE)
|
||||
{
|
||||
RemoveFromHashCache(it++);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We might free up enough just with "normal" removals above.
|
||||
if (might_need_cache_purge)
|
||||
{
|
||||
might_need_cache_purge = (m_hash_cache.size() > MAX_HASH_CACHE_SIZE);
|
||||
if (might_need_cache_purge)
|
||||
s_hash_cache_purge_list.emplace_back(it, static_cast<s32>(e.age));
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
// Pushing to a list, sorting, and removing ends up faster than re-iterating the map.
|
||||
if (might_need_cache_purge)
|
||||
{
|
||||
std::sort(s_hash_cache_purge_list.begin(), s_hash_cache_purge_list.end(),
|
||||
[](const auto& lhs, const auto& rhs) { return lhs.second - rhs.second; });
|
||||
|
||||
const u32 entries_to_purge = std::min(static_cast<u32>(m_hash_cache.size() - MAX_HASH_CACHE_SIZE),
|
||||
static_cast<u32>(s_hash_cache_purge_list.size()));
|
||||
for (u32 i = 0; i < entries_to_purge; i++)
|
||||
RemoveFromHashCache(s_hash_cache_purge_list[i].first);
|
||||
}
|
||||
}
|
||||
|
||||
GSTextureCache::Target* GSTextureCache::CreateTarget(const GIFRegTEX0& TEX0, int w, int h, float scale, int type, const bool clear)
|
||||
{
|
||||
ASSERT(type == RenderTarget || type == DepthStencil);
|
||||
@@ -4154,7 +4213,7 @@ void GSTextureCache::Source::UpdateLayer(const GIFRegTEX0& TEX0, const GSVector4
|
||||
void GSTextureCache::Source::Write(const GSVector4i& r, int layer, const GSOffset& off)
|
||||
{
|
||||
if (!m_write.rect)
|
||||
m_write.rect = static_cast<GSVector4i*>(_aligned_malloc(3 * sizeof(GSVector4i), 32));
|
||||
m_write.rect = static_cast<GSVector4i*>(_aligned_malloc(3 * sizeof(GSVector4i), 16));
|
||||
|
||||
m_write.rect[m_write.count++] = r;
|
||||
|
||||
@@ -4214,6 +4273,8 @@ void GSTextureCache::Source::Flush(u32 count, int layer, const GSOffset& off)
|
||||
rtx = psm.rtxP;
|
||||
}
|
||||
|
||||
pitch = VectorAlign(pitch);
|
||||
|
||||
for (u32 i = 0; i < count; i++)
|
||||
{
|
||||
const GSVector4i r(m_write.rect[i]);
|
||||
@@ -4385,7 +4446,7 @@ void GSTextureCache::Target::Update(bool reset_age)
|
||||
}
|
||||
else
|
||||
{
|
||||
const int pitch = Common::AlignUpPow2(r.width() * sizeof(u32), 32);
|
||||
const int pitch = VectorAlign(r.width() * sizeof(u32));
|
||||
g_gs_renderer->m_mem.ReadTexture(off, r, s_unswizzle_buffer, pitch, TEXA);
|
||||
|
||||
t->Update(t_r, s_unswizzle_buffer, pitch);
|
||||
@@ -5127,13 +5188,13 @@ GSTextureCache::SourceRegion GSTextureCache::SourceRegion::AdjustForMipmap(u32 l
|
||||
if (HasX())
|
||||
{
|
||||
const u32 new_minx = GetMinX() >> level;
|
||||
const u32 new_maxx = std::max<u32>(GetMaxX() >> level, new_minx + 1);
|
||||
const u32 new_maxx = new_minx + std::max(GetWidth() >> level, 1u);
|
||||
ret.SetX(new_minx, new_maxx);
|
||||
}
|
||||
if (HasY())
|
||||
{
|
||||
const u32 new_miny = GetMinY() >> level;
|
||||
const u32 new_maxy = std::max<u32>(GetMaxY() >> level, new_miny + 1);
|
||||
const u32 new_maxy = new_miny + std::max(GetHeight() >> level, 1u);
|
||||
ret.SetY(new_miny, new_maxy);
|
||||
}
|
||||
return ret;
|
||||
@@ -5241,7 +5302,7 @@ static void HashTextureLevel(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, GST
|
||||
{
|
||||
// Expand texture indices. Align to 32 bytes for AVX2.
|
||||
const bool palette = (psm.pal > 0);
|
||||
const u32 pitch = Common::AlignUpPow2(static_cast<u32>(block_rect.z) << (palette ? 0 : 2), 32);
|
||||
const u32 pitch = VectorAlign(static_cast<u32>(block_rect.z) << (palette ? 0 : 2));
|
||||
const u32 row_size = static_cast<u32>(tw) << (palette ? 0 : 2);
|
||||
const GSLocalMemory::readTexture rtx = palette ? psm.rtxP : psm.rtx;
|
||||
|
||||
@@ -5317,8 +5378,7 @@ void GSTextureCache::PreloadTexture(const GIFRegTEX0& TEX0, const GIFRegTEXA& TE
|
||||
}
|
||||
else
|
||||
{
|
||||
// Align pitch to 32 bytes for AVX2 if we're going through the temp buffer path.
|
||||
pitch = Common::AlignUpPow2(pitch, 32);
|
||||
pitch = VectorAlign(pitch);
|
||||
|
||||
u8* buff = s_unswizzle_buffer;
|
||||
rtx(mem, off, block_rect, buff, pitch, TEXA);
|
||||
|
||||
@@ -123,6 +123,8 @@ public:
|
||||
bool is_replacement;
|
||||
};
|
||||
|
||||
using HashCacheMap = std::unordered_map<HashCacheKey, HashCacheEntry, HashCacheKeyHash>;
|
||||
|
||||
class Surface : public GSAlignedClass<32>
|
||||
{
|
||||
protected:
|
||||
@@ -374,7 +376,7 @@ protected:
|
||||
PaletteMap m_palette_map;
|
||||
SourceMap m_src;
|
||||
u64 m_source_memory_usage = 0;
|
||||
std::unordered_map<HashCacheKey, HashCacheEntry, HashCacheKeyHash> m_hash_cache;
|
||||
HashCacheMap m_hash_cache;
|
||||
u64 m_hash_cache_memory_usage = 0;
|
||||
u64 m_hash_cache_replacement_memory_usage = 0;
|
||||
|
||||
@@ -402,6 +404,8 @@ protected:
|
||||
bool PrepareDownloadTexture(u32 width, u32 height, GSTexture::Format format, std::unique_ptr<GSDownloadTexture>* tex);
|
||||
|
||||
HashCacheEntry* LookupHashCache(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, bool& paltex, const u32* clut, const GSVector2i* lod, SourceRegion region);
|
||||
void RemoveFromHashCache(HashCacheMap::iterator it);
|
||||
void AgeHashCache();
|
||||
|
||||
static void PreloadTexture(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, SourceRegion region, GSLocalMemory& mem, bool paltex, GSTexture* tex, u32 level);
|
||||
static HashType HashTexture(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, SourceRegion region);
|
||||
|
||||
@@ -209,6 +209,7 @@ std::optional<TextureName> GSTextureReplacements::ParseReplacementName(const std
|
||||
&ret.bits, &extension_dot) == 4 &&
|
||||
extension_dot == '.')
|
||||
{
|
||||
ret.CLUTHash = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -225,6 +226,7 @@ std::optional<TextureName> GSTextureReplacements::ParseReplacementName(const std
|
||||
3 &&
|
||||
extension_dot == '.')
|
||||
{
|
||||
ret.CLUTHash = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -371,6 +371,7 @@ void GSDeviceMTL::EndRenderPass()
|
||||
if (m_current_render.encoder)
|
||||
{
|
||||
EndDebugGroup(m_current_render.encoder);
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, 1);
|
||||
if (m_spin_timer)
|
||||
[m_current_render.encoder updateFence:m_spin_fence afterStages:MTLRenderStageFragment];
|
||||
[m_current_render.encoder endEncoding];
|
||||
@@ -1240,53 +1241,51 @@ static bool s_capture_next = false;
|
||||
|
||||
GSDevice::PresentResult GSDeviceMTL::BeginPresent(bool frame_skip)
|
||||
{ @autoreleasepool {
|
||||
GSDeviceMTL* dev = static_cast<GSDeviceMTL*>(g_gs_device.get());
|
||||
if (dev && m_capture_start_frame && dev->FrameNo() == m_capture_start_frame)
|
||||
if (m_capture_start_frame && FrameNo() == m_capture_start_frame)
|
||||
s_capture_next = true;
|
||||
if (frame_skip || m_window_info.type == WindowInfo::Type::Surfaceless || !g_gs_device)
|
||||
{
|
||||
ImGui::EndFrame();
|
||||
return PresentResult::FrameSkipped;
|
||||
}
|
||||
id<MTLCommandBuffer> buf = dev->GetRenderCmdBuf();
|
||||
id<MTLCommandBuffer> buf = GetRenderCmdBuf();
|
||||
m_current_drawable = MRCRetain([m_layer nextDrawable]);
|
||||
dev->EndRenderPass();
|
||||
EndRenderPass();
|
||||
if (!m_current_drawable)
|
||||
{
|
||||
[buf pushDebugGroup:@"Present Skipped"];
|
||||
[buf popDebugGroup];
|
||||
dev->FlushEncoders();
|
||||
FlushEncoders();
|
||||
ImGui::EndFrame();
|
||||
return PresentResult::FrameSkipped;
|
||||
}
|
||||
[m_pass_desc colorAttachments][0].texture = [m_current_drawable texture];
|
||||
id<MTLRenderCommandEncoder> enc = [buf renderCommandEncoderWithDescriptor:m_pass_desc];
|
||||
[enc setLabel:@"Present"];
|
||||
dev->m_current_render.encoder = MRCRetain(enc);
|
||||
m_current_render.encoder = MRCRetain(enc);
|
||||
return PresentResult::OK;
|
||||
}}
|
||||
|
||||
void GSDeviceMTL::EndPresent()
|
||||
{ @autoreleasepool {
|
||||
GSDeviceMTL* dev = static_cast<GSDeviceMTL*>(g_gs_device.get());
|
||||
pxAssertDev(dev && dev->m_current_render.encoder && dev->m_current_render_cmdbuf, "BeginPresent cmdbuf was destroyed");
|
||||
pxAssertDev(m_current_render.encoder && m_current_render_cmdbuf, "BeginPresent cmdbuf was destroyed");
|
||||
ImGui::Render();
|
||||
dev->RenderImGui(ImGui::GetDrawData());
|
||||
dev->EndRenderPass();
|
||||
RenderImGui(ImGui::GetDrawData());
|
||||
EndRenderPass();
|
||||
if (m_current_drawable)
|
||||
{
|
||||
const bool use_present_drawable = m_use_present_drawable == UsePresentDrawable::Always ||
|
||||
(m_use_present_drawable == UsePresentDrawable::IfVsync && m_vsync_mode != VsyncMode::Off);
|
||||
|
||||
if (use_present_drawable)
|
||||
[dev->m_current_render_cmdbuf presentDrawable:m_current_drawable];
|
||||
[m_current_render_cmdbuf presentDrawable:m_current_drawable];
|
||||
else
|
||||
[dev->m_current_render_cmdbuf addScheduledHandler:[drawable = std::move(m_current_drawable)](id<MTLCommandBuffer>){
|
||||
[m_current_render_cmdbuf addScheduledHandler:[drawable = std::move(m_current_drawable)](id<MTLCommandBuffer>){
|
||||
[drawable present];
|
||||
}];
|
||||
}
|
||||
dev->FlushEncoders();
|
||||
dev->FrameCompleted();
|
||||
FlushEncoders();
|
||||
FrameCompleted();
|
||||
m_current_drawable = nullptr;
|
||||
if (m_capture_start_frame)
|
||||
{
|
||||
@@ -2178,7 +2177,7 @@ void GSDeviceMTL::SendHWDraw(GSHWDrawConfig& config, id<MTLRenderCommandEncoder>
|
||||
textureBarrier(enc);
|
||||
[enc drawIndexedPrimitives:topology
|
||||
indexCount:count
|
||||
indexType:MTLIndexTypeUInt32
|
||||
indexType:MTLIndexTypeUInt16
|
||||
indexBuffer:buffer
|
||||
indexBufferOffset:off + p * sizeof(*config.indices)];
|
||||
p += count;
|
||||
@@ -2200,7 +2199,7 @@ void GSDeviceMTL::SendHWDraw(GSHWDrawConfig& config, id<MTLRenderCommandEncoder>
|
||||
textureBarrier(enc);
|
||||
[enc drawIndexedPrimitives:topology
|
||||
indexCount:config.indices_per_prim
|
||||
indexType:MTLIndexTypeUInt32
|
||||
indexType:MTLIndexTypeUInt16
|
||||
indexBuffer:buffer
|
||||
indexBufferOffset:off + p * sizeof(*config.indices)];
|
||||
}
|
||||
@@ -2217,7 +2216,7 @@ void GSDeviceMTL::SendHWDraw(GSHWDrawConfig& config, id<MTLRenderCommandEncoder>
|
||||
|
||||
[enc drawIndexedPrimitives:topology
|
||||
indexCount:config.nindices
|
||||
indexType:MTLIndexTypeUInt32
|
||||
indexType:MTLIndexTypeUInt16
|
||||
indexBuffer:buffer
|
||||
indexBufferOffset:off];
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ bool GSDeviceOGL::Create(const WindowInfo& wi, VsyncMode vsync)
|
||||
GLint max_vertex_ssbos = 0;
|
||||
glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &max_vertex_ssbos);
|
||||
DevCon.WriteLn("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: %d", max_vertex_ssbos);
|
||||
m_features.vs_expand = (max_vertex_ssbos > 0);
|
||||
m_features.vs_expand = (max_vertex_ssbos > 0 && GLAD_GL_ARB_gpu_shader5);
|
||||
}
|
||||
if (!m_features.vs_expand)
|
||||
Console.Warning("Vertex expansion is not supported. This will reduce performance.");
|
||||
@@ -876,8 +876,8 @@ void GSDeviceOGL::DrawPrimitive()
|
||||
void GSDeviceOGL::DrawIndexedPrimitive()
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
|
||||
glDrawElementsBaseVertex(m_draw_topology, static_cast<u32>(m_index.count), GL_UNSIGNED_INT,
|
||||
reinterpret_cast<void*>(static_cast<u32>(m_index.start) * sizeof(u32)), static_cast<GLint>(m_vertex.start));
|
||||
glDrawElementsBaseVertex(m_draw_topology, static_cast<u32>(m_index.count), GL_UNSIGNED_SHORT,
|
||||
reinterpret_cast<void*>(static_cast<u32>(m_index.start) * sizeof(u16)), static_cast<GLint>(m_vertex.start));
|
||||
}
|
||||
|
||||
void GSDeviceOGL::DrawIndexedPrimitive(int offset, int count)
|
||||
@@ -885,8 +885,8 @@ void GSDeviceOGL::DrawIndexedPrimitive(int offset, int count)
|
||||
//ASSERT(offset + count <= (int)m_index.count);
|
||||
|
||||
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
|
||||
glDrawElementsBaseVertex(m_draw_topology, count, GL_UNSIGNED_INT,
|
||||
reinterpret_cast<void*>((static_cast<u32>(m_index.start) + static_cast<u32>(offset)) * sizeof(u32)),
|
||||
glDrawElementsBaseVertex(m_draw_topology, count, GL_UNSIGNED_SHORT,
|
||||
reinterpret_cast<void*>((static_cast<u32>(m_index.start) + static_cast<u32>(offset)) * sizeof(u16)),
|
||||
static_cast<GLint>(m_vertex.start));
|
||||
}
|
||||
|
||||
@@ -1134,7 +1134,9 @@ std::string GSDeviceOGL::GenGlslHeader(const std::string_view& entry, GLenum typ
|
||||
else
|
||||
{
|
||||
header = "#version 330 core\n";
|
||||
header += "#extension GL_ARB_shading_language_420pack: require\n";
|
||||
header += "#extension GL_ARB_shading_language_420pack : require\n";
|
||||
if (GLAD_GL_ARB_gpu_shader5)
|
||||
header += "#extension GL_ARB_gpu_shader5 : require\n";
|
||||
if (m_features.vs_expand)
|
||||
header += "#extension GL_ARB_shader_storage_buffer_object: require\n";
|
||||
}
|
||||
@@ -1548,15 +1550,15 @@ void GSDeviceOGL::DrawMultiStretchRects(
|
||||
void GSDeviceOGL::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, const GSVector2& ds)
|
||||
{
|
||||
const u32 vertex_reserve_size = num_rects * 4 * sizeof(GSVertexPT1);
|
||||
const u32 index_reserve_size = num_rects * 6 * sizeof(u32);
|
||||
const u32 index_reserve_size = num_rects * 6 * sizeof(u16);
|
||||
auto vertex_map = m_vertex_stream_buffer->Map(sizeof(GSVertexPT1), vertex_reserve_size);
|
||||
auto index_map = m_index_stream_buffer->Map(sizeof(u32), index_reserve_size);
|
||||
auto index_map = m_index_stream_buffer->Map(sizeof(u16), index_reserve_size);
|
||||
m_vertex.start = vertex_map.index_aligned;
|
||||
m_index.start = index_map.index_aligned;
|
||||
|
||||
// Don't use primitive restart here, it ends up slower on some drivers.
|
||||
GSVertexPT1* verts = reinterpret_cast<GSVertexPT1*>(vertex_map.pointer);
|
||||
u32* idx = reinterpret_cast<u32*>(index_map.pointer);
|
||||
u16* idx = reinterpret_cast<u16*>(index_map.pointer);
|
||||
u32 icount = 0;
|
||||
u32 vcount = 0;
|
||||
for (u32 i = 0; i < num_rects; i++)
|
||||
@@ -1587,7 +1589,7 @@ void GSDeviceOGL::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rec
|
||||
m_vertex.count = vcount;
|
||||
m_index.count = icount;
|
||||
m_vertex_stream_buffer->Unmap(vcount * sizeof(GSVertexPT1));
|
||||
m_index_stream_buffer->Unmap(icount * sizeof(u32));
|
||||
m_index_stream_buffer->Unmap(icount * sizeof(u16));
|
||||
|
||||
PSSetShaderResource(0, rects[0].src);
|
||||
PSSetSamplerState(rects[0].linear ? m_convert.ln : m_convert.pt);
|
||||
@@ -1807,8 +1809,8 @@ void GSDeviceOGL::IASetVertexBuffer(const void* vertices, size_t count)
|
||||
|
||||
void GSDeviceOGL::IASetIndexBuffer(const void* index, size_t count)
|
||||
{
|
||||
const u32 size = static_cast<u32>(count) * sizeof(u32);
|
||||
auto res = m_index_stream_buffer->Map(sizeof(u32), size);
|
||||
const u32 size = static_cast<u32>(count) * sizeof(u16);
|
||||
auto res = m_index_stream_buffer->Map(sizeof(u16), size);
|
||||
m_index.start = res.index_aligned;
|
||||
m_index.count = count;
|
||||
std::memcpy(res.pointer, index, size);
|
||||
@@ -1999,18 +2001,7 @@ void GSDeviceOGL::RenderImGui()
|
||||
m_vertex_stream_buffer->Unmap(size);
|
||||
}
|
||||
|
||||
// Bit awkward, because this is using 16-bit indices, not 32-bit.
|
||||
u32 index_start;
|
||||
{
|
||||
static_assert(sizeof(ImDrawIdx) == sizeof(u16));
|
||||
|
||||
const u32 size = static_cast<u32>(cmd_list->IdxBuffer.Size) * sizeof(ImDrawIdx);
|
||||
auto res = m_index_stream_buffer->Map(sizeof(u16), size);
|
||||
index_start = res.index_aligned;
|
||||
std::memcpy(res.pointer, cmd_list->IdxBuffer.Data, size);
|
||||
m_index_stream_buffer->Unmap(size);
|
||||
m_index_stream_buffer->Bind();
|
||||
}
|
||||
IASetIndexBuffer(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size);
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
@@ -2038,7 +2029,7 @@ void GSDeviceOGL::RenderImGui()
|
||||
}
|
||||
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, GL_UNSIGNED_SHORT,
|
||||
(void*)(intptr_t)((pcmd->IdxOffset + index_start) * sizeof(ImDrawIdx)), pcmd->VtxOffset + vertex_start);
|
||||
(void*)(intptr_t)((pcmd->IdxOffset + m_index.start) * sizeof(ImDrawIdx)), pcmd->VtxOffset + vertex_start);
|
||||
}
|
||||
|
||||
g_perfmon.Put(GSPerfMon::DrawCalls, cmd_list->CmdBuffer.Size);
|
||||
@@ -2165,6 +2156,8 @@ void GSDeviceOGL::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVecto
|
||||
GSTextureOGL* RT = static_cast<GSTextureOGL*>(rt);
|
||||
GSTextureOGL* DS = static_cast<GSTextureOGL*>(ds);
|
||||
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(GLState::rt != RT || GLState::ds != DS));
|
||||
|
||||
OMSetFBO(m_fbo);
|
||||
if (rt)
|
||||
{
|
||||
@@ -2431,13 +2424,17 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
OMSetBlendState(config.blend.enable, s_gl_blend_factors[config.blend.src_factor],
|
||||
s_gl_blend_factors[config.blend.dst_factor], s_gl_blend_ops[config.blend.op],
|
||||
config.blend.constant_enable, config.blend.constant);
|
||||
OMSetColorMaskState(config.colormask);
|
||||
|
||||
// avoid changing framebuffer just to switch from rt+depth to rt and vice versa
|
||||
GSTexture* draw_rt = hdr_rt ? hdr_rt : config.rt;
|
||||
GSTexture* draw_ds = config.ds;
|
||||
if (!draw_ds && GLState::ds && GLState::rt == draw_rt && config.tex != GLState::ds &&
|
||||
GLState::ds->GetSize() == draw_rt->GetSize())
|
||||
OMColorMaskSelector draw_colormask = config.colormask;
|
||||
if (!draw_rt && GLState::rt && GLState::ds == draw_ds && GLState::rt->GetSize() == draw_ds->GetSize())
|
||||
{
|
||||
draw_rt = GLState::rt;
|
||||
draw_colormask.wrgba = 0;
|
||||
}
|
||||
else if (!draw_ds && GLState::ds && GLState::rt == draw_rt && GLState::ds->GetSize() == draw_rt->GetSize())
|
||||
{
|
||||
// should already be always-pass.
|
||||
draw_ds = GLState::ds;
|
||||
@@ -2446,6 +2443,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
|
||||
OMSetRenderTargets(draw_rt, draw_ds, &config.scissor);
|
||||
OMSetColorMaskState(draw_colormask);
|
||||
SetupOM(config.depth);
|
||||
|
||||
SendHWDraw(config, psel.ps.IsFeedbackLoop());
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "GS/Renderers/OpenGL/GSDeviceOGL.h"
|
||||
#include "GS/Renderers/OpenGL/GSTextureOGL.h"
|
||||
#include "GS/Renderers/OpenGL/GLState.h"
|
||||
#include "GS/GSExtra.h"
|
||||
#include "GS/GSPerfMon.h"
|
||||
#include "GS/GSPng.h"
|
||||
#include "GS/GSGL.h"
|
||||
@@ -476,7 +477,7 @@ std::unique_ptr<GSDownloadTextureOGL> GSDownloadTextureOGL::Create(u32 width, u3
|
||||
}
|
||||
|
||||
// Fallback to glReadPixels() + CPU buffer.
|
||||
u8* cpu_buffer = static_cast<u8*>(_aligned_malloc(buffer_size, 32));
|
||||
u8* cpu_buffer = static_cast<u8*>(_aligned_malloc(buffer_size, VECTOR_ALIGNMENT));
|
||||
if (!cpu_buffer)
|
||||
return {};
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ typedef GSVector4 VectorF;
|
||||
#define LOCAL_STEP local.d4
|
||||
#endif
|
||||
|
||||
void GSDrawScanline::CSetupPrim(const GSVertexSW* vertex, const u32* index, const GSVertexSW& dscan, GSScanlineLocalData& local)
|
||||
void GSDrawScanline::CSetupPrim(const GSVertexSW* vertex, const u16* index, const GSVertexSW& dscan, GSScanlineLocalData& local)
|
||||
{
|
||||
const GSScanlineGlobalData& global = GlobalFromLocal(local);
|
||||
GSScanlineSelector sel = global.sel;
|
||||
@@ -451,10 +451,14 @@ __ri static void WritePixel(const T& src, int addr, int i, u32 psm, const GSScan
|
||||
}
|
||||
|
||||
void GSDrawScanline::CDrawScanline(int pixels, int left, int top, const GSVertexSW& scan, GSScanlineLocalData& local)
|
||||
{
|
||||
CDrawScanline(pixels, left, top, scan, local, GlobalFromLocal(local).sel);
|
||||
}
|
||||
|
||||
__ri void GSDrawScanline::CDrawScanline(int pixels, int left, int top, const GSVertexSW& scan, GSScanlineLocalData& local, GSScanlineSelector sel)
|
||||
{
|
||||
const GSScanlineGlobalData& global = GlobalFromLocal(local);
|
||||
|
||||
GSScanlineSelector sel = global.sel;
|
||||
constexpr int vlen = sizeof(VectorF) / sizeof(float);
|
||||
|
||||
#if _M_SSE < 0x501
|
||||
@@ -1729,17 +1733,10 @@ void GSDrawScanline::CDrawScanline(int pixels, int left, int top, const GSVertex
|
||||
|
||||
void GSDrawScanline::CDrawEdge(int pixels, int left, int top, const GSVertexSW& scan, GSScanlineLocalData& local)
|
||||
{
|
||||
// This sucks. But so does not jitting!
|
||||
const GSScanlineGlobalData* old_gd = local.gd;
|
||||
GSScanlineGlobalData gd;
|
||||
std::memcpy(&gd, &local.gd, sizeof(gd));
|
||||
gd.sel.zwrite = 0;
|
||||
gd.sel.edge = 1;
|
||||
local.gd = &gd;
|
||||
|
||||
CDrawScanline(pixels, left, top, scan, local);
|
||||
|
||||
local.gd = old_gd;
|
||||
GSScanlineSelector sel = local.gd->sel;
|
||||
sel.zwrite = 0;
|
||||
sel.edge = 1;
|
||||
CDrawScanline(pixels, left, top, scan, local, sel);
|
||||
}
|
||||
|
||||
template <class T, bool masked>
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
~GSDrawScanline() override;
|
||||
|
||||
/// Function pointer types which we call back into.
|
||||
using SetupPrimPtr = void(*)(const GSVertexSW* vertex, const u32* index, const GSVertexSW& dscan, GSScanlineLocalData& local);
|
||||
using SetupPrimPtr = void(*)(const GSVertexSW* vertex, const u16* index, const GSVertexSW& dscan, GSScanlineLocalData& local);
|
||||
using DrawScanlinePtr = void(*)(int pixels, int left, int top, const GSVertexSW& scan, GSScanlineLocalData& local);
|
||||
|
||||
/// Flushes the code cache, forcing everything to be recompiled.
|
||||
@@ -60,9 +60,10 @@ private:
|
||||
GSCodeGeneratorFunctionMap<GSSetupPrimCodeGenerator, u64, SetupPrimPtr> m_sp_map;
|
||||
GSCodeGeneratorFunctionMap<GSDrawScanlineCodeGenerator, u64, DrawScanlinePtr> m_ds_map;
|
||||
|
||||
static void CSetupPrim(const GSVertexSW* vertex, const u32* index, const GSVertexSW& dscan, GSScanlineLocalData& local);
|
||||
static void CSetupPrim(const GSVertexSW* vertex, const u16* index, const GSVertexSW& dscan, GSScanlineLocalData& local);
|
||||
static void CDrawScanline(int pixels, int left, int top, const GSVertexSW& scan, GSScanlineLocalData& local);
|
||||
static void CDrawEdge(int pixels, int left, int top, const GSVertexSW& scan, GSScanlineLocalData& local);
|
||||
__ri static void CDrawScanline(int pixels, int left, int top, const GSVertexSW& scan, GSScanlineLocalData& local, GSScanlineSelector sel);
|
||||
};
|
||||
|
||||
MULTI_ISA_UNSHARED_END
|
||||
|
||||
@@ -91,7 +91,8 @@ GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(u64 key, void* code, si
|
||||
|
||||
if (shouldUseCDrawScanline(key))
|
||||
{
|
||||
jmp(reinterpret_cast<const void*>(&GSDrawScanline::CDrawScanline));
|
||||
jmp(reinterpret_cast<const void*>(static_cast<void (*)(int, int, int, const GSVertexSW&, GSScanlineLocalData&)>(
|
||||
&GSDrawScanline::CDrawScanline)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ GSRasterizer::GSRasterizer(GSDrawScanline* ds, int id, int threads)
|
||||
|
||||
m_thread_height = compute_best_thread_height(threads);
|
||||
|
||||
m_edge.buff = static_cast<GSVertexSW*>(_aligned_malloc(sizeof(GSVertexSW) * 2048, 32));
|
||||
m_edge.buff = static_cast<GSVertexSW*>(_aligned_malloc(sizeof(GSVertexSW) * 2048, VECTOR_ALIGNMENT));
|
||||
m_edge.count = 0;
|
||||
if (!m_edge.buff)
|
||||
throw std::bad_alloc();
|
||||
@@ -154,10 +154,10 @@ void GSRasterizer::Draw(GSRasterizerData& data)
|
||||
const GSVertexSW* vertex = data.vertex;
|
||||
const GSVertexSW* vertex_end = data.vertex + data.vertex_count;
|
||||
|
||||
const u32* index = data.index;
|
||||
const u32* index_end = data.index + data.index_count;
|
||||
const u16* index = data.index;
|
||||
const u16* index_end = data.index + data.index_count;
|
||||
|
||||
u32 tmp_index[] = {0, 1, 2};
|
||||
static constexpr u16 tmp_index[] = {0, 1, 2};
|
||||
|
||||
bool scissor_test = !data.bbox.eq(data.bbox.rintersect(data.scissor));
|
||||
|
||||
@@ -261,7 +261,7 @@ void GSRasterizer::Draw(GSRasterizerData& data)
|
||||
}
|
||||
|
||||
template <bool scissor_test>
|
||||
void GSRasterizer::DrawPoint(const GSVertexSW* vertex, int vertex_count, const u32* index, int index_count)
|
||||
void GSRasterizer::DrawPoint(const GSVertexSW* vertex, int vertex_count, const u16* index, int index_count)
|
||||
{
|
||||
m_primcount++;
|
||||
|
||||
@@ -286,7 +286,7 @@ void GSRasterizer::DrawPoint(const GSVertexSW* vertex, int vertex_count, const u
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 tmp_index[1] = {0};
|
||||
static constexpr u16 tmp_index[1] = {0};
|
||||
|
||||
for (int i = 0; i < vertex_count; i++, vertex++)
|
||||
{
|
||||
@@ -307,7 +307,7 @@ void GSRasterizer::DrawPoint(const GSVertexSW* vertex, int vertex_count, const u
|
||||
}
|
||||
}
|
||||
|
||||
void GSRasterizer::DrawLine(const GSVertexSW* vertex, const u32* index)
|
||||
void GSRasterizer::DrawLine(const GSVertexSW* vertex, const u16* index)
|
||||
{
|
||||
m_primcount++;
|
||||
|
||||
@@ -425,7 +425,7 @@ static const u8 s_ysort[8][4] =
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
|
||||
void GSRasterizer::DrawTriangle(const GSVertexSW* vertex, const u32* index)
|
||||
void GSRasterizer::DrawTriangle(const GSVertexSW* vertex, const u16* index)
|
||||
{
|
||||
m_primcount++;
|
||||
|
||||
@@ -606,7 +606,7 @@ void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW2& RESTRIC
|
||||
|
||||
#else
|
||||
|
||||
void GSRasterizer::DrawTriangle(const GSVertexSW* vertex, const u32* index)
|
||||
void GSRasterizer::DrawTriangle(const GSVertexSW* vertex, const u16* index)
|
||||
{
|
||||
m_primcount++;
|
||||
|
||||
@@ -784,7 +784,7 @@ void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW& RESTRICT
|
||||
|
||||
#endif
|
||||
|
||||
void GSRasterizer::DrawSprite(const GSVertexSW* vertex, const u32* index)
|
||||
void GSRasterizer::DrawSprite(const GSVertexSW* vertex, const u16* index)
|
||||
{
|
||||
m_primcount++;
|
||||
|
||||
@@ -1082,7 +1082,7 @@ void GSRasterizer::AddScanline(GSVertexSW* e, int pixels, int left, int top, con
|
||||
AddScanlineInfo(e, pixels, left, top);
|
||||
}
|
||||
|
||||
void GSRasterizer::Flush(const GSVertexSW* vertex, const u32* index, const GSVertexSW& dscan, bool edge /* = false */)
|
||||
void GSRasterizer::Flush(const GSVertexSW* vertex, const u16* index, const GSVertexSW& dscan, bool edge /* = false */)
|
||||
{
|
||||
// TODO: on win64 this could be the place where xmm6-15 are preserved (not by each DrawScanline)
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
u8* buff;
|
||||
GSVertexSW* vertex;
|
||||
int vertex_count;
|
||||
u32* index;
|
||||
u16* index;
|
||||
int index_count;
|
||||
u64 frame;
|
||||
u64 start;
|
||||
@@ -101,10 +101,10 @@ protected:
|
||||
__forceinline bool HasEdge() const { return (m_draw_edge != nullptr); }
|
||||
|
||||
template <bool scissor_test>
|
||||
void DrawPoint(const GSVertexSW* vertex, int vertex_count, const u32* index, int index_count);
|
||||
void DrawLine(const GSVertexSW* vertex, const u32* index);
|
||||
void DrawTriangle(const GSVertexSW* vertex, const u32* index);
|
||||
void DrawSprite(const GSVertexSW* vertex, const u32* index);
|
||||
void DrawPoint(const GSVertexSW* vertex, int vertex_count, const u16* index, int index_count);
|
||||
void DrawLine(const GSVertexSW* vertex, const u16* index);
|
||||
void DrawTriangle(const GSVertexSW* vertex, const u16* index);
|
||||
void DrawSprite(const GSVertexSW* vertex, const u16* index);
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
__forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW2& RESTRICT edge, const GSVertexSW2& RESTRICT dedge, const GSVertexSW2& RESTRICT dscan, const GSVector4& RESTRICT p0);
|
||||
@@ -115,7 +115,7 @@ protected:
|
||||
void DrawEdge(const GSVertexSW& v0, const GSVertexSW& v1, const GSVertexSW& dv, int orientation, int side);
|
||||
|
||||
__forceinline void AddScanline(GSVertexSW* e, int pixels, int left, int top, const GSVertexSW& scan);
|
||||
__forceinline void Flush(const GSVertexSW* vertex, const u32* index, const GSVertexSW& dscan, bool edge = false);
|
||||
__forceinline void Flush(const GSVertexSW* vertex, const u16* index, const GSVertexSW& dscan, bool edge = false);
|
||||
|
||||
__forceinline void DrawScanline(int pixels, int left, int top, const GSVertexSW& scan);
|
||||
__forceinline void DrawEdge(int pixels, int left, int top, const GSVertexSW& scan);
|
||||
|
||||
@@ -39,7 +39,7 @@ GSRendererSW::GSRendererSW(int threads)
|
||||
m_tc = std::make_unique<GSTextureCacheSW>();
|
||||
m_rl = GSRasterizerList::Create(threads);
|
||||
|
||||
m_output = (u8*)_aligned_malloc(1024 * 1024 * sizeof(u32), 32);
|
||||
m_output = (u8*)_aligned_malloc(1024 * 1024 * sizeof(u32), VECTOR_ALIGNMENT);
|
||||
|
||||
std::fill(std::begin(m_fzb_pages), std::end(m_fzb_pages), 0);
|
||||
std::fill(std::begin(m_tex_pages), std::end(m_tex_pages), 0);
|
||||
@@ -78,7 +78,7 @@ void GSRendererSW::Destroy()
|
||||
m_output = nullptr;
|
||||
}
|
||||
|
||||
void GSRendererSW::VSync(u32 field, bool registers_written)
|
||||
void GSRendererSW::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
{
|
||||
Sync(0); // IncAge might delete a cached texture in use
|
||||
|
||||
@@ -99,7 +99,7 @@ void GSRendererSW::VSync(u32 field, bool registers_written)
|
||||
//
|
||||
*/
|
||||
|
||||
GSRenderer::VSync(field, registers_written);
|
||||
GSRenderer::VSync(field, registers_written, idle_frame);
|
||||
|
||||
m_tc->IncAge();
|
||||
|
||||
@@ -118,7 +118,7 @@ GSTexture* GSRendererSW::GetOutput(int i, float& scale, int& y_offset)
|
||||
int w = curFramebuffer.FBW * 64;
|
||||
int h = framebufferSize.y;
|
||||
|
||||
if (g_gs_device->ResizeTarget(&m_texture[index], w, h))
|
||||
if (g_gs_device->ResizeRenderTarget(&m_texture[index], w, h, false, false))
|
||||
{
|
||||
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[curFramebuffer.PSM];
|
||||
constexpr int pitch = 1024 * 4;
|
||||
@@ -343,7 +343,7 @@ void GSRendererSW::Draw()
|
||||
sd->buff = (u8*)m_vertex_heap.alloc(sizeof(GSVertexSW) * ((m_vertex.next + 1) & ~1) + sizeof(u32) * m_index.tail, 64);
|
||||
sd->vertex = (GSVertexSW*)sd->buff;
|
||||
sd->vertex_count = m_vertex.next;
|
||||
sd->index = (u32*)(sd->buff + sizeof(GSVertexSW) * ((m_vertex.next + 1) & ~1));
|
||||
sd->index = (u16*)(sd->buff + sizeof(GSVertexSW) * ((m_vertex.next + 1) & ~1));
|
||||
sd->index_count = m_index.tail;
|
||||
sd->scanmsk_value = m_draw_env->SCANMSK.MSK;
|
||||
|
||||
@@ -354,7 +354,7 @@ void GSRendererSW::Draw()
|
||||
|
||||
GSVertexSW::s_cvb[m_vt.m_primclass][PRIM->TME][PRIM->FST][q_div](m_context, sd->vertex, m_vertex.buff, m_vertex.next);
|
||||
|
||||
memcpy(sd->index, m_index.buff, sizeof(u32) * m_index.tail);
|
||||
std::memcpy(sd->index, m_index.buff, sizeof(u16) * m_index.tail);
|
||||
|
||||
GSVector4i scissor = GSVector4i(context->scissor.in);
|
||||
GSVector4i bbox = GSVector4i(m_vt.m_min.p.floor().xyxy(m_vt.m_max.p.ceil()));
|
||||
@@ -1046,7 +1046,7 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
|
||||
{
|
||||
gd.sel.tlu = 1;
|
||||
|
||||
gd.clut = (u32*)m_vertex_heap.alloc(sizeof(u32) * 256, 32); // FIXME: might address uninitialized data of the texture (0xCD) that is not in 0-15 range for 4-bpp formats
|
||||
gd.clut = (u32*)m_vertex_heap.alloc(sizeof(u32) * 256, VECTOR_ALIGNMENT); // FIXME: might address uninitialized data of the texture (0xCD) that is not in 0-15 range for 4-bpp formats
|
||||
|
||||
memcpy(gd.clut, (const u32*)m_mem.m_clut, sizeof(u32) * GSLocalMemory::m_psm[context->TEX0.PSM].pal);
|
||||
}
|
||||
@@ -1333,7 +1333,7 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
|
||||
ExpandDIMX(m_dimx, env.DIMX);
|
||||
}
|
||||
|
||||
gd.dimx = (GSVector4i*)m_vertex_heap.alloc(sizeof(m_dimx), 32);
|
||||
gd.dimx = (GSVector4i*)m_vertex_heap.alloc(sizeof(m_dimx), VECTOR_ALIGNMENT);
|
||||
|
||||
std::memcpy(gd.dimx, m_dimx, sizeof(m_dimx));
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ protected:
|
||||
GSVector4i m_dimx[8] = {};
|
||||
|
||||
void Reset(bool hardware_reset) override;
|
||||
void VSync(u32 field, bool registers_written) override;
|
||||
void VSync(u32 field, bool registers_written, bool idle_frame) override;
|
||||
GSTexture* GetOutput(int i, float& scale, int& y_offset) override;
|
||||
GSTexture* GetFeedbackOutput(float& scale) override;
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ void GSSetupPrimCodeGenerator2::Depth_XMM()
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
mov(eax, ptr[_index + sizeof(u32) * 1]);
|
||||
movzx(eax, word[_index + sizeof(u16) * 1]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
add(rax, _64_vertex);
|
||||
|
||||
@@ -299,7 +299,7 @@ void GSSetupPrimCodeGenerator2::Depth_YMM()
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
mov(eax, ptr[_index + sizeof(u32) * 1]);
|
||||
movzx(eax, word[_index + sizeof(u16) * 1]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
add(rax, _64_vertex);
|
||||
|
||||
@@ -504,7 +504,7 @@ void GSSetupPrimCodeGenerator2::Color()
|
||||
|
||||
if (!(m_sel.prim == GS_SPRITE_CLASS && (m_en.z || m_en.f))) // if this is a sprite, the last vertex was already loaded in Depth()
|
||||
{
|
||||
mov(eax, ptr[_index + sizeof(u32) * last]);
|
||||
movzx(eax, word[_index + sizeof(u16) * last]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
add(rax, _64_vertex);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSTextureCacheSW.h"
|
||||
#include "GS/Renderers/SW/GSTextureCacheSW.h"
|
||||
#include "GS/GSExtra.h"
|
||||
|
||||
GSTextureCacheSW::GSTextureCacheSW() = default;
|
||||
|
||||
@@ -233,14 +234,11 @@ bool GSTextureCacheSW::Texture::Update(const GSVector4i& rect)
|
||||
|
||||
if (m_buff == NULL)
|
||||
{
|
||||
u32 pitch = (1 << m_tw) << shift;
|
||||
const u32 pitch = (1 << m_tw) << shift;
|
||||
|
||||
m_buff = _aligned_malloc(pitch * th * 4, 32);
|
||||
|
||||
if (m_buff == NULL)
|
||||
{
|
||||
m_buff = _aligned_malloc(pitch * th * 4, VECTOR_ALIGNMENT);
|
||||
if (!m_buff)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GSLocalMemory& mem = g_gs_renderer->m_mem;
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSTextureSW.h"
|
||||
#include "GS/Renderers/SW/GSTextureSW.h"
|
||||
#include "GS/GSExtra.h"
|
||||
#include "GS/GSPng.h"
|
||||
|
||||
GSTextureSW::GSTextureSW(Type type, int width, int height)
|
||||
@@ -24,7 +25,7 @@ GSTextureSW::GSTextureSW(Type type, int width, int height)
|
||||
m_type = type;
|
||||
m_format = Format::Invalid;
|
||||
m_pitch = ((width << 2) + 31) & ~31;
|
||||
m_data = _aligned_malloc(m_pitch * height, 32);
|
||||
m_data = _aligned_malloc(m_pitch * height, VECTOR_ALIGNMENT);
|
||||
}
|
||||
|
||||
GSTextureSW::~GSTextureSW()
|
||||
|
||||
@@ -475,6 +475,7 @@ void GSDeviceVK::EndPresent()
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
m_swap_chain->GetCurrentTexture().TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, 1);
|
||||
|
||||
g_vulkan_context->SubmitCommandBuffer(m_swap_chain.get(), !m_swap_chain->IsPresentModeSynchronizing());
|
||||
g_vulkan_context->MoveToNextCommandBuffer();
|
||||
@@ -578,7 +579,7 @@ bool GSDeviceVK::CheckFeatures()
|
||||
const bool isAMD = (vendorID == 0x1002 || vendorID == 0x1022);
|
||||
// const bool isNVIDIA = (vendorID == 0x10DE);
|
||||
|
||||
m_features.framebuffer_fetch = g_vulkan_context->GetOptionalExtensions().vk_arm_rasterization_order_attachment_access && !GSConfig.DisableFramebufferFetch;
|
||||
m_features.framebuffer_fetch = g_vulkan_context->GetOptionalExtensions().vk_ext_rasterization_order_attachment_access && !GSConfig.DisableFramebufferFetch;
|
||||
m_features.texture_barrier = GSConfig.OverrideTextureBarriers != 0;
|
||||
m_features.broken_point_sampler = isAMD;
|
||||
// Usually, geometry shader indicates primid support
|
||||
@@ -955,13 +956,13 @@ void GSDeviceVK::DoMultiStretchRects(
|
||||
{
|
||||
// Set up vertices first.
|
||||
const u32 vertex_reserve_size = num_rects * 4 * sizeof(GSVertexPT1);
|
||||
const u32 index_reserve_size = num_rects * 6 * sizeof(u32);
|
||||
const u32 index_reserve_size = num_rects * 6 * sizeof(u16);
|
||||
if (!m_vertex_stream_buffer.ReserveMemory(vertex_reserve_size, sizeof(GSVertexPT1)) ||
|
||||
!m_index_stream_buffer.ReserveMemory(index_reserve_size, sizeof(u32)))
|
||||
!m_index_stream_buffer.ReserveMemory(index_reserve_size, sizeof(u16)))
|
||||
{
|
||||
ExecuteCommandBufferAndRestartRenderPass(false, "Uploading bytes to vertex buffer");
|
||||
if (!m_vertex_stream_buffer.ReserveMemory(vertex_reserve_size, sizeof(GSVertexPT1)) ||
|
||||
!m_index_stream_buffer.ReserveMemory(index_reserve_size, sizeof(u32)))
|
||||
!m_index_stream_buffer.ReserveMemory(index_reserve_size, sizeof(u16)))
|
||||
{
|
||||
pxFailRel("Failed to reserve space for vertices");
|
||||
}
|
||||
@@ -971,7 +972,7 @@ void GSDeviceVK::DoMultiStretchRects(
|
||||
// Don't use primitive restart here, it ends up slower on some drivers.
|
||||
const GSVector2 ds(static_cast<float>(dTex->GetWidth()), static_cast<float>(dTex->GetHeight()));
|
||||
GSVertexPT1* verts = reinterpret_cast<GSVertexPT1*>(m_vertex_stream_buffer.GetCurrentHostPointer());
|
||||
u32* idx = reinterpret_cast<u32*>(m_index_stream_buffer.GetCurrentHostPointer());
|
||||
u16* idx = reinterpret_cast<u16*>(m_index_stream_buffer.GetCurrentHostPointer());
|
||||
u32 icount = 0;
|
||||
u32 vcount = 0;
|
||||
for (u32 i = 0; i < num_rects; i++)
|
||||
@@ -1001,11 +1002,11 @@ void GSDeviceVK::DoMultiStretchRects(
|
||||
|
||||
m_vertex.start = m_vertex_stream_buffer.GetCurrentOffset() / sizeof(GSVertexPT1);
|
||||
m_vertex.count = vcount;
|
||||
m_index.start = m_index_stream_buffer.GetCurrentOffset() / sizeof(u32);
|
||||
m_index.start = m_index_stream_buffer.GetCurrentOffset() / sizeof(u16);
|
||||
m_index.count = icount;
|
||||
m_vertex_stream_buffer.CommitMemory(vcount * sizeof(GSVertexPT1));
|
||||
m_index_stream_buffer.CommitMemory(icount * sizeof(u32));
|
||||
SetIndexBuffer(m_index_stream_buffer.GetBuffer(), 0, VK_INDEX_TYPE_UINT32);
|
||||
m_index_stream_buffer.CommitMemory(icount * sizeof(u16));
|
||||
SetIndexBuffer(m_index_stream_buffer.GetBuffer(), 0, VK_INDEX_TYPE_UINT16);
|
||||
|
||||
// Even though we're batching, a cmdbuffer submit could've messed this up.
|
||||
const GSVector4i rc(dTex->GetRect());
|
||||
@@ -1368,21 +1369,21 @@ void GSDeviceVK::IASetVertexBuffer(const void* vertex, size_t stride, size_t cou
|
||||
|
||||
void GSDeviceVK::IASetIndexBuffer(const void* index, size_t count)
|
||||
{
|
||||
const u32 size = sizeof(u32) * static_cast<u32>(count);
|
||||
if (!m_index_stream_buffer.ReserveMemory(size, sizeof(u32)))
|
||||
const u32 size = sizeof(u16) * static_cast<u32>(count);
|
||||
if (!m_index_stream_buffer.ReserveMemory(size, sizeof(u16)))
|
||||
{
|
||||
ExecuteCommandBufferAndRestartRenderPass(false, "Uploading bytes to index buffer");
|
||||
if (!m_index_stream_buffer.ReserveMemory(size, sizeof(u32)))
|
||||
if (!m_index_stream_buffer.ReserveMemory(size, sizeof(u16)))
|
||||
pxFailRel("Failed to reserve space for vertices");
|
||||
}
|
||||
|
||||
m_index.start = m_index_stream_buffer.GetCurrentOffset() / sizeof(u32);
|
||||
m_index.start = m_index_stream_buffer.GetCurrentOffset() / sizeof(u16);
|
||||
m_index.count = count;
|
||||
|
||||
std::memcpy(m_index_stream_buffer.GetCurrentHostPointer(), index, size);
|
||||
m_index_stream_buffer.CommitMemory(size);
|
||||
|
||||
SetIndexBuffer(m_index_stream_buffer.GetBuffer(), 0, VK_INDEX_TYPE_UINT32);
|
||||
SetIndexBuffer(m_index_stream_buffer.GetBuffer(), 0, VK_INDEX_TYPE_UINT16);
|
||||
}
|
||||
|
||||
void GSDeviceVK::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor, FeedbackLoopFlag feedback_loop)
|
||||
@@ -1529,6 +1530,15 @@ static void AddUtilityVertexAttributes(Vulkan::GraphicsPipelineBuilder& gpb)
|
||||
gpb.SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
|
||||
}
|
||||
|
||||
static void SetPipelineProvokingVertex(const GSDevice::FeatureSupport& features, Vulkan::GraphicsPipelineBuilder& gpb)
|
||||
{
|
||||
// We enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass.
|
||||
// Normally we wouldn't enable it on the present/swap chain, but apparently the rule is it applies to the last
|
||||
// pipeline bound before the render pass begun, and in this case, we can't bind null.
|
||||
if (features.provoking_vertex_last)
|
||||
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
|
||||
}
|
||||
|
||||
VkShaderModule GSDeviceVK::GetUtilityVertexShader(const std::string& source, const char* replace_main = nullptr)
|
||||
{
|
||||
std::stringstream ss;
|
||||
@@ -1769,6 +1779,7 @@ bool GSDeviceVK::CompileConvertPipelines()
|
||||
ScopedGuard vs_guard([&vs]() { Vulkan::Util::SafeDestroyShaderModule(vs); });
|
||||
|
||||
Vulkan::GraphicsPipelineBuilder gpb;
|
||||
SetPipelineProvokingVertex(m_features, gpb);
|
||||
AddUtilityVertexAttributes(gpb);
|
||||
gpb.SetPipelineLayout(m_utility_pipeline_layout);
|
||||
gpb.SetDynamicViewportAndScissorState();
|
||||
@@ -1777,10 +1788,6 @@ bool GSDeviceVK::CompileConvertPipelines()
|
||||
gpb.SetNoBlendingState();
|
||||
gpb.SetVertexShader(vs);
|
||||
|
||||
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
|
||||
if (m_features.provoking_vertex_last)
|
||||
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
|
||||
|
||||
for (ShaderConvert i = ShaderConvert::COPY; static_cast<int>(i) < static_cast<int>(ShaderConvert::Count);
|
||||
i = static_cast<ShaderConvert>(static_cast<int>(i) + 1))
|
||||
{
|
||||
@@ -1964,6 +1971,7 @@ bool GSDeviceVK::CompilePresentPipelines()
|
||||
ScopedGuard vs_guard([&vs]() { Vulkan::Util::SafeDestroyShaderModule(vs); });
|
||||
|
||||
Vulkan::GraphicsPipelineBuilder gpb;
|
||||
SetPipelineProvokingVertex(m_features, gpb);
|
||||
AddUtilityVertexAttributes(gpb);
|
||||
gpb.SetPipelineLayout(m_utility_pipeline_layout);
|
||||
gpb.SetDynamicViewportAndScissorState();
|
||||
@@ -1975,10 +1983,6 @@ bool GSDeviceVK::CompilePresentPipelines()
|
||||
gpb.SetNoStencilState();
|
||||
gpb.SetRenderPass(m_swap_chain_render_pass, 0);
|
||||
|
||||
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
|
||||
if (m_features.provoking_vertex_last)
|
||||
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
|
||||
|
||||
for (PresentShader i = PresentShader::COPY; static_cast<int>(i) < static_cast<int>(PresentShader::Count);
|
||||
i = static_cast<PresentShader>(static_cast<int>(i) + 1))
|
||||
{
|
||||
@@ -2023,6 +2027,7 @@ bool GSDeviceVK::CompileInterlacePipelines()
|
||||
ScopedGuard vs_guard([&vs]() { Vulkan::Util::SafeDestroyShaderModule(vs); });
|
||||
|
||||
Vulkan::GraphicsPipelineBuilder gpb;
|
||||
SetPipelineProvokingVertex(m_features, gpb);
|
||||
AddUtilityVertexAttributes(gpb);
|
||||
gpb.SetPipelineLayout(m_utility_pipeline_layout);
|
||||
gpb.SetDynamicViewportAndScissorState();
|
||||
@@ -2033,10 +2038,6 @@ bool GSDeviceVK::CompileInterlacePipelines()
|
||||
gpb.SetRenderPass(rp, 0);
|
||||
gpb.SetVertexShader(vs);
|
||||
|
||||
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
|
||||
if (m_features.provoking_vertex_last)
|
||||
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(m_interlace.size()); i++)
|
||||
{
|
||||
VkShaderModule ps = GetUtilityFragmentShader(*shader, StringUtil::StdStringFromFormat("ps_main%d", i).c_str());
|
||||
@@ -2077,6 +2078,7 @@ bool GSDeviceVK::CompileMergePipelines()
|
||||
ScopedGuard vs_guard([&vs]() { Vulkan::Util::SafeDestroyShaderModule(vs); });
|
||||
|
||||
Vulkan::GraphicsPipelineBuilder gpb;
|
||||
SetPipelineProvokingVertex(m_features, gpb);
|
||||
AddUtilityVertexAttributes(gpb);
|
||||
gpb.SetPipelineLayout(m_utility_pipeline_layout);
|
||||
gpb.SetDynamicViewportAndScissorState();
|
||||
@@ -2086,10 +2088,6 @@ bool GSDeviceVK::CompileMergePipelines()
|
||||
gpb.SetRenderPass(rp, 0);
|
||||
gpb.SetVertexShader(vs);
|
||||
|
||||
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
|
||||
if (m_features.provoking_vertex_last)
|
||||
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(m_merge.size()); i++)
|
||||
{
|
||||
VkShaderModule ps = GetUtilityFragmentShader(*shader, StringUtil::StdStringFromFormat("ps_main%d", i).c_str());
|
||||
@@ -2119,6 +2117,7 @@ bool GSDeviceVK::CompilePostProcessingPipelines()
|
||||
return false;
|
||||
|
||||
Vulkan::GraphicsPipelineBuilder gpb;
|
||||
SetPipelineProvokingVertex(m_features, gpb);
|
||||
AddUtilityVertexAttributes(gpb);
|
||||
gpb.SetPipelineLayout(m_utility_pipeline_layout);
|
||||
gpb.SetDynamicViewportAndScissorState();
|
||||
@@ -2128,10 +2127,6 @@ bool GSDeviceVK::CompilePostProcessingPipelines()
|
||||
gpb.SetNoBlendingState();
|
||||
gpb.SetRenderPass(rp, 0);
|
||||
|
||||
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
|
||||
if (m_features.provoking_vertex_last)
|
||||
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
|
||||
|
||||
{
|
||||
std::optional<std::string> vshader = Host::ReadResourceFileToString("shaders/vulkan/convert.glsl");
|
||||
if (!vshader)
|
||||
@@ -2267,6 +2262,7 @@ bool GSDeviceVK::CompileImGuiPipeline()
|
||||
ScopedGuard ps_guard([&ps]() { Vulkan::Util::SafeDestroyShaderModule(ps); });
|
||||
|
||||
Vulkan::GraphicsPipelineBuilder gpb;
|
||||
SetPipelineProvokingVertex(m_features, gpb);
|
||||
gpb.SetPipelineLayout(m_utility_pipeline_layout);
|
||||
gpb.SetRenderPass(m_swap_chain_render_pass, 0);
|
||||
gpb.AddVertexBuffer(0, sizeof(ImDrawVert), VK_VERTEX_INPUT_RATE_VERTEX);
|
||||
@@ -2319,9 +2315,6 @@ void GSDeviceVK::RenderImGui()
|
||||
m_dirty_flags |= DIRTY_FLAG_UTILITY_TEXTURE;
|
||||
}
|
||||
|
||||
// imgui uses 16-bit indices
|
||||
SetIndexBuffer(m_index_stream_buffer.GetBuffer(), 0, VK_INDEX_TYPE_UINT16);
|
||||
|
||||
// this is for presenting, we don't want to screw with the viewport/scissor set by display
|
||||
m_dirty_flags &= ~(DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR);
|
||||
|
||||
@@ -2343,19 +2336,8 @@ void GSDeviceVK::RenderImGui()
|
||||
m_vertex_stream_buffer.CommitMemory(size);
|
||||
}
|
||||
|
||||
u32 index_offset;
|
||||
{
|
||||
const u32 size = sizeof(ImDrawIdx) * static_cast<u32>(cmd_list->IdxBuffer.Size);
|
||||
if (!m_index_stream_buffer.ReserveMemory(size, sizeof(ImDrawIdx)))
|
||||
{
|
||||
Console.Warning("Skipping ImGui draw because of no vertex buffer space");
|
||||
return;
|
||||
}
|
||||
|
||||
index_offset = m_index_stream_buffer.GetCurrentOffset() / sizeof(ImDrawIdx);
|
||||
std::memcpy(m_index_stream_buffer.GetCurrentHostPointer(), cmd_list->IdxBuffer.Data, size);
|
||||
m_index_stream_buffer.CommitMemory(size);
|
||||
}
|
||||
static_assert(sizeof(ImDrawIdx) == sizeof(u16));
|
||||
IASetIndexBuffer(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size);
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
@@ -2366,7 +2348,7 @@ void GSDeviceVK::RenderImGui()
|
||||
if ((clip.zwzw() <= clip.xyxy()).mask() != 0)
|
||||
continue;
|
||||
|
||||
SetScissor(GSVector4i(clip));
|
||||
SetScissor(GSVector4i(clip).max_i32(GSVector4i::zero()));
|
||||
|
||||
// Since we don't have the GSTexture...
|
||||
Vulkan::Texture* tex = static_cast<Vulkan::Texture*>(pcmd->GetTexID());
|
||||
@@ -2379,7 +2361,7 @@ void GSDeviceVK::RenderImGui()
|
||||
if (ApplyUtilityState())
|
||||
{
|
||||
vkCmdDrawIndexed(g_vulkan_context->GetCurrentCommandBuffer(), pcmd->ElemCount, 1,
|
||||
index_offset + pcmd->IdxOffset, vertex_offset + pcmd->VtxOffset, 0);
|
||||
m_index.start + pcmd->IdxOffset, vertex_offset + pcmd->VtxOffset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2655,6 +2637,7 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p)
|
||||
return VK_NULL_HANDLE;
|
||||
|
||||
Vulkan::GraphicsPipelineBuilder gpb;
|
||||
SetPipelineProvokingVertex(m_features, gpb);
|
||||
|
||||
// Common state
|
||||
gpb.SetPipelineLayout(m_tfx_pipeline_layout);
|
||||
@@ -2739,14 +2722,11 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p)
|
||||
VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, p.cms.wrgba);
|
||||
}
|
||||
|
||||
if (m_features.provoking_vertex_last)
|
||||
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
|
||||
|
||||
// Tests have shown that it's faster to just enable rast order on the entire pass, rather than alternating
|
||||
// between turning it on and off for different draws, and adding the required barrier between non-rast-order
|
||||
// and rast-order draws.
|
||||
if (m_features.framebuffer_fetch && p.IsRTFeedbackLoop())
|
||||
gpb.AddBlendFlags(VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM);
|
||||
gpb.AddBlendFlags(VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT);
|
||||
|
||||
VkPipeline pipeline = gpb.Create(g_vulkan_context->GetDevice(), g_vulkan_shader_cache->GetPipelineCache(true));
|
||||
if (pipeline)
|
||||
@@ -2786,7 +2766,7 @@ void GSDeviceVK::InitializeState()
|
||||
m_vertex_buffer_offset = 0;
|
||||
m_index_buffer = m_index_stream_buffer.GetBuffer();
|
||||
m_index_buffer_offset = 0;
|
||||
m_index_type = VK_INDEX_TYPE_UINT32;
|
||||
m_index_type = VK_INDEX_TYPE_UINT16;
|
||||
m_current_framebuffer = VK_NULL_HANDLE;
|
||||
m_current_render_pass = VK_NULL_HANDLE;
|
||||
|
||||
@@ -2864,7 +2844,12 @@ void GSDeviceVK::ExecuteCommandBufferAndRestartRenderPass(bool wait_for_completi
|
||||
Console.Warning("Vulkan: Executing command buffer due to '%s'", reason);
|
||||
|
||||
const VkRenderPass render_pass = m_current_render_pass;
|
||||
const GSVector4i render_pass_area(m_current_render_pass_area);
|
||||
const GSVector4i render_pass_area = m_current_render_pass_area;
|
||||
const GSVector4i scissor = m_scissor;
|
||||
GSTexture* const current_rt = m_current_render_target;
|
||||
GSTexture* const current_ds = m_current_depth_target;
|
||||
const FeedbackLoopFlag current_feedback_loop = m_current_framebuffer_feedback_loop;
|
||||
|
||||
EndRenderPass();
|
||||
g_vulkan_context->ExecuteCommandBuffer(GetWaitType(wait_for_completion, GSConfig.HWSpinCPUForReadbacks));
|
||||
InvalidateCachedState();
|
||||
@@ -2872,8 +2857,7 @@ void GSDeviceVK::ExecuteCommandBufferAndRestartRenderPass(bool wait_for_completi
|
||||
if (render_pass != VK_NULL_HANDLE)
|
||||
{
|
||||
// rebind framebuffer
|
||||
ApplyBaseState(m_dirty_flags, g_vulkan_context->GetCurrentCommandBuffer());
|
||||
m_dirty_flags &= ~DIRTY_BASE_STATE;
|
||||
OMSetRenderTargets(current_rt, current_ds, scissor, current_feedback_loop);
|
||||
|
||||
// restart render pass
|
||||
BeginRenderPass(render_pass, render_pass_area);
|
||||
@@ -2906,6 +2890,15 @@ void GSDeviceVK::InvalidateCachedState()
|
||||
m_dirty_flags |= DIRTY_FLAG_VERTEX_BUFFER;
|
||||
if (m_index_buffer != VK_NULL_HANDLE)
|
||||
m_dirty_flags |= DIRTY_FLAG_INDEX_BUFFER;
|
||||
|
||||
for (u32 i = 0; i < NUM_TFX_TEXTURES; i++)
|
||||
m_tfx_textures[i] = &m_null_texture;
|
||||
m_utility_texture = &m_null_texture;
|
||||
m_current_framebuffer = VK_NULL_HANDLE;
|
||||
m_current_render_target = nullptr;
|
||||
m_current_depth_target = nullptr;
|
||||
m_current_framebuffer_feedback_loop = FeedbackLoopFlag_None;
|
||||
|
||||
m_current_pipeline_layout = PipelineLayout::Undefined;
|
||||
m_tfx_descriptor_sets[1] = VK_NULL_HANDLE;
|
||||
m_tfx_descriptor_sets[2] = VK_NULL_HANDLE;
|
||||
@@ -3113,9 +3106,10 @@ void GSDeviceVK::EndRenderPass()
|
||||
if (m_current_render_pass == VK_NULL_HANDLE)
|
||||
return;
|
||||
|
||||
vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
|
||||
m_current_render_pass = VK_NULL_HANDLE;
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, 1);
|
||||
|
||||
vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
}
|
||||
|
||||
void GSDeviceVK::SetViewport(const VkViewport& viewport)
|
||||
@@ -3648,13 +3642,19 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
(!hdr_rt && DATE_rp != DATE_RENDER_PASS_STENCIL_ONE && CheckRenderPassArea(render_area));
|
||||
|
||||
// render pass restart optimizations
|
||||
if (render_area_okay)
|
||||
if (render_area_okay && (m_current_render_target == draw_rt || m_current_depth_target == draw_ds))
|
||||
{
|
||||
// avoid restarting the render pass just to switch from rt+depth to rt and vice versa
|
||||
if (!draw_ds && m_current_depth_target && m_current_render_target == draw_rt &&
|
||||
config.tex != m_current_depth_target && m_current_depth_target->GetSize() == draw_rt->GetSize() &&
|
||||
((pipe.feedback_loop_flags & FeedbackLoopFlag_ReadAndWriteRT) ==
|
||||
(m_current_framebuffer_feedback_loop & FeedbackLoopFlag_ReadAndWriteRT)))
|
||||
// keep the depth even if doing HDR draws, because the next draw will probably re-enable depth
|
||||
if (!draw_rt && m_current_render_target && config.tex != m_current_render_target &&
|
||||
m_current_render_target->GetSize() == draw_ds->GetSize())
|
||||
{
|
||||
draw_rt = m_current_render_target;
|
||||
m_pipeline_selector.rt = true;
|
||||
m_pipeline_selector.cms.wrgba = 0;
|
||||
}
|
||||
else if (!draw_ds && m_current_depth_target && config.tex != m_current_depth_target &&
|
||||
m_current_depth_target->GetSize() == draw_rt->GetSize())
|
||||
{
|
||||
draw_ds = m_current_depth_target;
|
||||
m_pipeline_selector.ds = true;
|
||||
@@ -3663,9 +3663,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
|
||||
// Prefer keeping feedback loop enabled, that way we're not constantly restarting render passes
|
||||
pipe.feedback_loop_flags |= (m_current_render_target == draw_rt && m_current_depth_target == draw_ds) ?
|
||||
m_current_framebuffer_feedback_loop :
|
||||
0;
|
||||
pipe.feedback_loop_flags |= m_current_framebuffer_feedback_loop;
|
||||
}
|
||||
|
||||
// We don't need the very first barrier if this is the first draw after switching to feedback loop,
|
||||
@@ -3833,7 +3831,8 @@ void GSDeviceVK::UpdateHWPipelineSelector(GSHWDrawConfig& config, PipelineSelect
|
||||
(config.ps.IsFeedbackLoop() || config.require_one_barrier || config.require_full_barrier)) ?
|
||||
FeedbackLoopFlag_ReadAndWriteRT :
|
||||
FeedbackLoopFlag_None;
|
||||
pipe.feedback_loop_flags |= (config.tex == config.ds) ? FeedbackLoopFlag_ReadDS : FeedbackLoopFlag_None;
|
||||
pipe.feedback_loop_flags |=
|
||||
(config.tex && config.tex == config.ds) ? FeedbackLoopFlag_ReadDS : FeedbackLoopFlag_None;
|
||||
|
||||
// enable point size in the vertex shader if we're rendering points regardless of upscaling.
|
||||
pipe.vs.point_size |= (config.topology == GSHWDrawConfig::Topology::Point);
|
||||
@@ -3847,7 +3846,7 @@ void GSDeviceVK::UploadHWDrawVerticesAndIndices(const GSHWDrawConfig& config)
|
||||
{
|
||||
m_index.start = 0;
|
||||
m_index.count = config.nindices;
|
||||
SetIndexBuffer(m_expand_index_buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
SetIndexBuffer(m_expand_index_buffer, 0, VK_INDEX_TYPE_UINT16);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -394,10 +394,10 @@ namespace R5900
|
||||
MakeOpcode0( MFC0, CopDefault, 0 );
|
||||
MakeOpcode0( MTC0, CopDefault, 0 );
|
||||
|
||||
MakeOpcode0( BC0F, Branch, 0 );
|
||||
MakeOpcode0( BC0T, Branch, 0 );
|
||||
MakeOpcode0( BC0FL, Branch, 0 );
|
||||
MakeOpcode0( BC0TL, Branch, 0 );
|
||||
MakeOpcode0(BC0F, Branch, IS_BRANCH | BRANCHTYPE_BC0 | CONDTYPE_EQ);
|
||||
MakeOpcode0(BC0T, Branch, IS_BRANCH | BRANCHTYPE_BC0 | CONDTYPE_NE);
|
||||
MakeOpcode0(BC0FL, Branch, IS_BRANCH | BRANCHTYPE_BC0 | CONDTYPE_EQ | IS_LIKELY);
|
||||
MakeOpcode0(BC0TL, Branch, IS_BRANCH | BRANCHTYPE_BC0 | CONDTYPE_NE | IS_LIKELY);
|
||||
|
||||
MakeOpcode0( TLBR, CopDefault, 0 );
|
||||
MakeOpcode0( TLBWI, CopDefault, 0 );
|
||||
|
||||
@@ -61,13 +61,14 @@ void COP2_Unknown();
|
||||
#define CONDTYPE_LTZ (0x05 << 0)
|
||||
#define CONDTYPE_GEZ (0x06 << 0)
|
||||
|
||||
#define BRANCHTYPE_MASK (0x07 << 3)
|
||||
#define BRANCHTYPE_MASK (0x0F << 3)
|
||||
#define BRANCHTYPE_JUMP (0x01 << 3)
|
||||
#define BRANCHTYPE_BRANCH (0x02 << 3)
|
||||
#define BRANCHTYPE_SYSCALL (0x03 << 3)
|
||||
#define BRANCHTYPE_ERET (0x04 << 3)
|
||||
#define BRANCHTYPE_REGISTER (0x05 << 3)
|
||||
#define BRANCHTYPE_BC1 (0x06 << 3)
|
||||
#define BRANCHTYPE_BC0 (0x08 << 3)
|
||||
|
||||
#define ALUTYPE_MASK (0x07 << 3)
|
||||
#define ALUTYPE_ADD (0x01 << 3)
|
||||
|
||||
@@ -316,6 +316,7 @@ __fi void vif1Interrupt()
|
||||
CPU_INT(DMAC_VIF1, 128);
|
||||
if (gifRegs.stat.APATH == 3)
|
||||
vif1Regs.stat.VGW = 1; //We're waiting for path 3. Gunslinger II
|
||||
CPU_SET_DMASTALL(DMAC_VIF1, true);
|
||||
return;
|
||||
}
|
||||
vif1Regs.stat.VGW = 0; //Path 3 isn't busy so we don't need to wait for it.
|
||||
|
||||
@@ -83,7 +83,10 @@ static __fi void vuExecMicro(int idx, u32 addr, bool requires_wait)
|
||||
|
||||
vifFlush(idx);
|
||||
if (GetVifX.waitforvu)
|
||||
{
|
||||
CPU_SET_DMASTALL(idx ? DMAC_VIF1 : DMAC_VIF0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vifRegs.itops > (idx ? 0x3ffu : 0xffu))
|
||||
{
|
||||
@@ -220,7 +223,10 @@ vifOp(vifCode_Flush)
|
||||
}
|
||||
|
||||
if (vif1.waitforvu || vif1Regs.stat.VGW)
|
||||
{
|
||||
CPU_SET_DMASTALL(DMAC_VIF1, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vif1.cmd = 0;
|
||||
vif1.pass = 0;
|
||||
@@ -250,7 +256,10 @@ vifOp(vifCode_FlushA)
|
||||
}
|
||||
|
||||
if (vif1.waitforvu || vif1Regs.stat.VGW)
|
||||
{
|
||||
CPU_SET_DMASTALL(DMAC_VIF1, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vif1.cmd = 0;
|
||||
vif1.pass = 0;
|
||||
@@ -268,7 +277,10 @@ vifOp(vifCode_FlushE)
|
||||
vifFlush(idx);
|
||||
|
||||
if (vifX.waitforvu)
|
||||
{
|
||||
CPU_SET_DMASTALL(idx ? DMAC_VIF1 : DMAC_VIF0, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vifX.cmd = 0;
|
||||
vifX.pass = 0;
|
||||
@@ -373,7 +385,10 @@ vifOp(vifCode_MPG)
|
||||
vifFlush(idx);
|
||||
|
||||
if (vifX.waitforvu)
|
||||
{
|
||||
CPU_SET_DMASTALL(idx ? DMAC_VIF1 : DMAC_VIF0, true);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
vifX.pass = 1;
|
||||
@@ -418,7 +433,10 @@ vifOp(vifCode_MSCAL)
|
||||
vifFlush(idx);
|
||||
|
||||
if (vifX.waitforvu)
|
||||
{
|
||||
CPU_SET_DMASTALL(idx ? DMAC_VIF1 : DMAC_VIF0, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vuExecMicro(idx, (u16)(vifXRegs.code), false);
|
||||
vifX.cmd = 0;
|
||||
@@ -454,7 +472,10 @@ vifOp(vifCode_MSCALF)
|
||||
}
|
||||
|
||||
if (vifX.waitforvu || vif1Regs.stat.VGW)
|
||||
{
|
||||
CPU_SET_DMASTALL(idx ? DMAC_VIF1 : DMAC_VIF0, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vuExecMicro(idx, (u16)(vifXRegs.code), true);
|
||||
vifX.cmd = 0;
|
||||
@@ -473,7 +494,10 @@ vifOp(vifCode_MSCNT)
|
||||
vifFlush(idx);
|
||||
|
||||
if (vifX.waitforvu)
|
||||
{
|
||||
CPU_SET_DMASTALL(idx ? DMAC_VIF1 : DMAC_VIF0, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vuExecMicro(idx, -1, false);
|
||||
vifX.cmd = 0;
|
||||
|
||||
@@ -311,7 +311,6 @@
|
||||
<ClCompile Include="GS\Renderers\SW\GSTextureSW.cpp" />
|
||||
<ClCompile Include="GS\GSUtil.cpp" />
|
||||
<ClCompile Include="GS\GSVector.cpp" />
|
||||
<ClCompile Include="GS\Renderers\Common\GSVertexList.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSVertexSW.cpp" />
|
||||
<ClCompile Include="GS\Renderers\Common\GSVertexTrace.cpp" />
|
||||
<ClCompile Include="GS\Renderers\Common\GSVertexTraceFMM.cpp" />
|
||||
@@ -646,7 +645,6 @@
|
||||
<ClInclude Include="GS\GSVector8.h" />
|
||||
<ClInclude Include="GS\Renderers\Common\GSVertex.h" />
|
||||
<ClInclude Include="GS\Renderers\HW\GSVertexHW.h" />
|
||||
<ClInclude Include="GS\Renderers\Common\GSVertexList.h" />
|
||||
<ClInclude Include="GS\Renderers\SW\GSVertexSW.h" />
|
||||
<ClInclude Include="GS\Renderers\Common\GSVertexTrace.h" />
|
||||
<ClInclude Include="GS\GSXXH.h" />
|
||||
|
||||
@@ -1133,9 +1133,6 @@
|
||||
<ClCompile Include="GS\Renderers\Common\GSVertexTraceFMM.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\Common\GSVertexList.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\Common\GSFunctionMap.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Common</Filter>
|
||||
</ClCompile>
|
||||
@@ -2020,9 +2017,6 @@
|
||||
<ClInclude Include="GS\Renderers\Common\GSVertexTrace.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\Common\GSVertexList.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\Common\GSVertex.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Common</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -1015,6 +1015,9 @@ public:
|
||||
microMapGPR& mapI = gprMap[i];
|
||||
if (mapI.VIreg == viLoadReg)
|
||||
{
|
||||
// Do this first, there is a case where when loadReg != writeReg, the findFreeGPR can steal the loadReg
|
||||
gprMap[i].count = this_counter;
|
||||
|
||||
if (viWriteReg >= 0) // Reg will be modified
|
||||
{
|
||||
if (viLoadReg != viWriteReg)
|
||||
@@ -1025,7 +1028,17 @@ public:
|
||||
// allocate a new register for writing to
|
||||
int x = findFreeGPR(viWriteReg);
|
||||
const xRegister32& gprX = xRegister32::GetInstance(x);
|
||||
|
||||
writeBackReg(gprX, true);
|
||||
|
||||
// writeReg not cached, needs backing up
|
||||
if (backup && gprMap[x].VIreg != viWriteReg)
|
||||
{
|
||||
xMOVZX(gprX, ptr16[&getVI(viWriteReg)]);
|
||||
writeVIBackup(gprX);
|
||||
backup = false;
|
||||
}
|
||||
|
||||
if (zext_if_dirty)
|
||||
xMOVZX(gprX, xRegister16(i));
|
||||
else
|
||||
@@ -1048,7 +1061,7 @@ public:
|
||||
xMOVZX(xRegister32(i), xRegister16(i));
|
||||
gprMap[i].isZeroExtended = true;
|
||||
}
|
||||
gprMap[i].count = this_counter;
|
||||
|
||||
gprMap[i].isNeeded = true;
|
||||
|
||||
if (backup)
|
||||
|
||||
@@ -24,7 +24,7 @@ import functools
|
||||
|
||||
src_dirs = [os.path.join(os.path.dirname(__file__), "..", "pcsx2"), os.path.join(os.path.dirname(__file__), "..", "pcsx2-qt")]
|
||||
fa_file = os.path.join(os.path.dirname(__file__), "..", "3rdparty", "include", "IconsFontAwesome5.h")
|
||||
dst_file = os.path.join(os.path.dirname(__file__), "..", "pcsx2", "Frontend", "ImguiManager.cpp")
|
||||
dst_file = os.path.join(os.path.dirname(__file__), "..", "pcsx2", "Frontend", "ImGuiManager.cpp")
|
||||
|
||||
all_source_files = list(functools.reduce(lambda prev, src_dir: prev + glob.glob(os.path.join(src_dir, "**", "*.cpp"), recursive=True) + \
|
||||
glob.glob(os.path.join(src_dir, "**", "*.h"), recursive=True) + \
|
||||
|
||||