mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
38 Commits
v2.7.44
...
gs_drawbuf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cdec6fb5a | ||
|
|
a1173c53d3 | ||
|
|
ac0deff9b2 | ||
|
|
3ae707464c | ||
|
|
00ef419023 | ||
|
|
448a279cd4 | ||
|
|
70e13adfde | ||
|
|
25bc280818 | ||
|
|
32e073002a | ||
|
|
911314e948 | ||
|
|
a73fcb343c | ||
|
|
251b2960f8 | ||
|
|
5bb99105c3 | ||
|
|
fa6e1b0949 | ||
|
|
4297918ce2 | ||
|
|
629a58469b | ||
|
|
5ff1eed28c | ||
|
|
4506ff1c46 | ||
|
|
4daa455524 | ||
|
|
433e99baec | ||
|
|
a1ac6662d3 | ||
|
|
87366cda9d | ||
|
|
edb2b37a92 | ||
|
|
4462b3f91d | ||
|
|
57ded8a022 | ||
|
|
304a7f9d30 | ||
|
|
73a09ffe6c | ||
|
|
4e5d7bd407 | ||
|
|
2a3452a489 | ||
|
|
2e7f951399 | ||
|
|
efb66c1d37 | ||
|
|
6fc88a4499 | ||
|
|
238b29836e | ||
|
|
58cbb61aac | ||
|
|
2c7a168029 | ||
|
|
bb4ee5f0fb | ||
|
|
1940fdb3d3 | ||
|
|
bf269e1295 |
@@ -20,7 +20,7 @@
|
||||
<url type="donation">https://github.com/sponsors/PCSX2</url>
|
||||
<url type="faq">https://pcsx2.net/docs/</url>
|
||||
<url type="help">https://pcsx2.net/discord</url>
|
||||
<url type="contribute">https://github.com/PCSX2/pcsx2/blob/master/.github/CONTRIBUTING.md</url>
|
||||
<url type="contribute">https://pcsx2.net/docs/category/contributing</url>
|
||||
<url type="translate">https://crowdin.com/project/pcsx2-emulator</url>
|
||||
<url type="contact">https://mastodon.social/@PCSX2</url>
|
||||
<screenshots>
|
||||
|
||||
@@ -65,6 +65,8 @@ set SHADERC_GLSLANG=7a47e2531cb334982b2a2dd8513dca0a3de4373d
|
||||
set SHADERC_SPIRVHEADERS=b824a462d4256d720bebb40e78b9eb8f78bbb305
|
||||
set SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
|
||||
|
||||
set AGILITYSDK=1.618.5
|
||||
|
||||
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 31490c781bacd2ce56862555b11c51c964977c39f14f51b817dfaecf0be089fe || goto error
|
||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1653.zip 140566abc64bb2320cb35f1d154d1cb3eb7174a12234d33bfdffb446bdc0a1d2 || goto error
|
||||
@@ -84,6 +86,7 @@ call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/r
|
||||
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v%KDDOCKWIDGETS%.zip" 47ddb48197872055f0adf8e90a7235f8a3b795ca1ee3a28ac2c504c673ae3806 || goto error
|
||||
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 4fe4e48f28aa80171b2166d45c0976ab0f21eecedb52cd4c3ef73b5afb48fac9 || goto error
|
||||
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
|
||||
call :downloadfile: "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" 0027fc24f947c48dbded13ada7d280be221eb651644e23a8a476f0f1f0a079dd || goto error
|
||||
|
||||
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" fab72d1a38eacea52710d18edb95dfd75db894ad869675d07a1eb26827da9b15 || goto error
|
||||
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 4a118247386ffba9160113f146f2189ba5abe3995db357114d7112ede6bd3cd1 || goto error
|
||||
@@ -305,6 +308,20 @@ cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo Unpacking Agility SDK
|
||||
rmdir /S /Q "agility-sdk-%AGILITYSDK%"
|
||||
%SEVENZIP% x -o"agility-sdk-%AGILITYSDK%" "agility-sdk-%AGILITYSDK%.nupkg" || goto error
|
||||
cd "agility-sdk-%AGILITYSDK%" || goto error
|
||||
if not exist "%INSTALLDIR%\bin\D3D12" (
|
||||
mkdir "%INSTALLDIR%\bin\D3D12" || goto error
|
||||
)
|
||||
rem the pdbs aren't in the list of distributable files, so only copy the dlls.
|
||||
copy "build\native\bin\arm64\D3D12Core.dll" "%INSTALLDIR%\bin\D3D12\D3D12Core.dll" || goto error
|
||||
if %DEBUG%==1 (
|
||||
copy "build\native\bin\arm64\d3d12SDKLayers.dll" "%INSTALLDIR%\bin\D3D12\d3d12SDKLayers.dll" || goto error
|
||||
)
|
||||
cd .. || goto error
|
||||
|
||||
echo Building shaderc...
|
||||
rmdir /S /Q "shaderc-%SHADERC%"
|
||||
%SEVENZIP% x "shaderc-%SHADERC%.zip" || goto error
|
||||
|
||||
@@ -63,6 +63,8 @@ set SHADERC_GLSLANG=7a47e2531cb334982b2a2dd8513dca0a3de4373d
|
||||
set SHADERC_SPIRVHEADERS=b824a462d4256d720bebb40e78b9eb8f78bbb305
|
||||
set SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
|
||||
|
||||
set AGILITYSDK=1.618.5
|
||||
|
||||
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 31490c781bacd2ce56862555b11c51c964977c39f14f51b817dfaecf0be089fe || goto error
|
||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1653.zip 140566abc64bb2320cb35f1d154d1cb3eb7174a12234d33bfdffb446bdc0a1d2 || goto error
|
||||
@@ -82,6 +84,7 @@ call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/r
|
||||
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v%KDDOCKWIDGETS%.zip" 47ddb48197872055f0adf8e90a7235f8a3b795ca1ee3a28ac2c504c673ae3806 || goto error
|
||||
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 4fe4e48f28aa80171b2166d45c0976ab0f21eecedb52cd4c3ef73b5afb48fac9 || goto error
|
||||
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
|
||||
call :downloadfile: "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" 0027fc24f947c48dbded13ada7d280be221eb651644e23a8a476f0f1f0a079dd || goto error
|
||||
|
||||
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" fab72d1a38eacea52710d18edb95dfd75db894ad869675d07a1eb26827da9b15 || goto error
|
||||
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 4a118247386ffba9160113f146f2189ba5abe3995db357114d7112ede6bd3cd1 || goto error
|
||||
@@ -302,6 +305,20 @@ cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo Unpacking Agility SDK
|
||||
rmdir /S /Q "agility-sdk-%AGILITYSDK%"
|
||||
%SEVENZIP% x -o"agility-sdk-%AGILITYSDK%" "agility-sdk-%AGILITYSDK%.nupkg" || goto error
|
||||
cd "agility-sdk-%AGILITYSDK%" || goto error
|
||||
if not exist "%INSTALLDIR%\bin\D3D12" (
|
||||
mkdir "%INSTALLDIR%\bin\D3D12" || goto error
|
||||
)
|
||||
rem the pdbs aren't in the list of distributable files, so only copy the dlls.
|
||||
copy "build\native\bin\x64\D3D12Core.dll" "%INSTALLDIR%\bin\D3D12\D3D12Core.dll" || goto error
|
||||
if %DEBUG%==1 (
|
||||
copy "build\native\bin\x64\d3d12SDKLayers.dll" "%INSTALLDIR%\bin\D3D12\d3d12SDKLayers.dll" || goto error
|
||||
)
|
||||
cd .. || goto error
|
||||
|
||||
echo Building shaderc...
|
||||
rmdir /S /Q "shaderc-%SHADERC%"
|
||||
%SEVENZIP% x "shaderc-%SHADERC%.zip" || goto error
|
||||
|
||||
4
3rdparty/rcheevos/CHANGELOG.md
vendored
4
3rdparty/rcheevos/CHANGELOG.md
vendored
@@ -1,3 +1,7 @@
|
||||
# v12.2.1
|
||||
* fix parsing of leaderboards with comparisons in legacy-formatted values
|
||||
* fix validation warning on long AddSource chains
|
||||
|
||||
# v12.2.0
|
||||
* add rc_client_create_subset_list
|
||||
* add rc_client_begin_fetch_game_titles
|
||||
|
||||
2
3rdparty/rcheevos/src/rc_version.h
vendored
2
3rdparty/rcheevos/src/rc_version.h
vendored
@@ -9,7 +9,7 @@ RC_BEGIN_C_DECLS
|
||||
|
||||
#define RCHEEVOS_VERSION_MAJOR 12
|
||||
#define RCHEEVOS_VERSION_MINOR 2
|
||||
#define RCHEEVOS_VERSION_PATCH 0
|
||||
#define RCHEEVOS_VERSION_PATCH 1
|
||||
|
||||
#define RCHEEVOS_MAKE_VERSION(major, minor, patch) (major * 1000000 + minor * 1000 + patch)
|
||||
#define RCHEEVOS_VERSION RCHEEVOS_MAKE_VERSION(RCHEEVOS_VERSION_MAJOR, RCHEEVOS_VERSION_MINOR, RCHEEVOS_VERSION_PATCH)
|
||||
|
||||
2
3rdparty/rcheevos/src/rcheevos/rc_validate.c
vendored
2
3rdparty/rcheevos/src/rcheevos/rc_validate.c
vendored
@@ -510,6 +510,7 @@ static void rc_combine_ranges(uint32_t* min_val, uint32_t* max_val, uint8_t oper
|
||||
break;
|
||||
|
||||
case RC_OPERATOR_ADD:
|
||||
case RC_OPERATOR_ADD_ACCUMULATOR:
|
||||
if (*min_val > *max_val) { /* underflow occurred */
|
||||
*max_val += oper_max_val;
|
||||
}
|
||||
@@ -522,6 +523,7 @@ static void rc_combine_ranges(uint32_t* min_val, uint32_t* max_val, uint8_t oper
|
||||
break;
|
||||
|
||||
case RC_OPERATOR_SUB:
|
||||
case RC_OPERATOR_SUB_ACCUMULATOR:
|
||||
*min_val -= oper_max_val;
|
||||
*max_val -= oper_min_val;
|
||||
break;
|
||||
|
||||
8
3rdparty/rcheevos/src/rcheevos/value.c
vendored
8
3rdparty/rcheevos/src/rcheevos/value.c
vendored
@@ -180,9 +180,11 @@ static void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_par
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rc_operator_is_modifying(cond->oper)) {
|
||||
parse->offset = RC_INVALID_OPERATOR;
|
||||
return;
|
||||
if (cond->type == RC_CONDITION_MEASURED && !rc_operator_is_modifying(cond->oper)) {
|
||||
/* ignore non-modifying operator on measured clause. if it were parsed as an AddSource
|
||||
* or SubSource, that would have already happened in rc_parse_condition_internal, and
|
||||
* legacy formatted values are essentially a series of AddSources. */
|
||||
cond->oper = RC_OPERATOR_NONE;
|
||||
}
|
||||
|
||||
rc_condition_update_parse_state(cond, parse);
|
||||
|
||||
@@ -4764,6 +4764,9 @@ SCES-50034:
|
||||
name: "MotoGP"
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
gpuTargetCLUT: 2 # Fixes some (haze?) shuffle colors.
|
||||
textureInsideRT: 1 # Fixes rendering artifacts on racers.
|
||||
SCES-50105:
|
||||
name: "Sky Odyssey"
|
||||
region: "PAL-M5"
|
||||
@@ -54743,6 +54746,9 @@ SLPS-20040:
|
||||
name-sort: "もとGP"
|
||||
name-en: "MotoGP"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
gpuTargetCLUT: 2 # Fixes some (haze?) shuffle colors.
|
||||
textureInsideRT: 1 # Fixes rendering artifacts on racers.
|
||||
SLPS-20041:
|
||||
name: "麻雀悟空 大聖"
|
||||
name-sort: "まーじゃんごくう たいせい"
|
||||
@@ -60491,7 +60497,6 @@ SLPS-25574:
|
||||
halfPixelOffset: 2 # Aligns effects.
|
||||
nativeScaling: 1 # Helps align effects.
|
||||
textureInsideRT: 1 # Fixes channel shuffles.
|
||||
preloadFrameData: 1 # Fixes menu graphics.
|
||||
autoFlush: 1 # Fixes motion blur.
|
||||
minimumBlendingLevel: 2 # Improves post effects.
|
||||
SLPS-25575:
|
||||
@@ -61216,7 +61221,6 @@ SLPS-25682:
|
||||
halfPixelOffset: 2 # Aligns effects.
|
||||
nativeScaling: 1 # Helps align effects.
|
||||
textureInsideRT: 1 # Fixes channel shuffles.
|
||||
preloadFrameData: 1 # Fixes menu graphics.
|
||||
autoFlush: 1 # Fixes motion blur.
|
||||
minimumBlendingLevel: 2 # Improves post effects.
|
||||
SLPS-25683:
|
||||
@@ -61846,7 +61850,6 @@ SLPS-25787:
|
||||
halfPixelOffset: 2 # Aligns effects.
|
||||
nativeScaling: 1 # Helps align effects.
|
||||
textureInsideRT: 1 # Fixes channel shuffles.
|
||||
preloadFrameData: 1 # Fixes menu graphics.
|
||||
autoFlush: 1 # Fixes motion blur.
|
||||
minimumBlendingLevel: 2 # Improves post effects.
|
||||
SLPS-25788:
|
||||
@@ -62258,7 +62261,6 @@ SLPS-25852:
|
||||
halfPixelOffset: 2 # Aligns effects.
|
||||
nativeScaling: 1 # Helps align effects.
|
||||
textureInsideRT: 1 # Fixes channel shuffles.
|
||||
preloadFrameData: 1 # Fixes menu graphics.
|
||||
autoFlush: 1 # Fixes motion blur.
|
||||
minimumBlendingLevel: 2 # Improves post effects.
|
||||
SLPS-25853:
|
||||
@@ -64233,6 +64235,9 @@ SLUS-20058:
|
||||
name: "MotoGP"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
gpuTargetCLUT: 2 # Fixes some (haze?) shuffle colors.
|
||||
textureInsideRT: 1 # Fixes rendering artifacts on racers.
|
||||
SLUS-20062:
|
||||
name: "Grand Theft Auto III"
|
||||
region: "NTSC-U"
|
||||
|
||||
@@ -168,6 +168,7 @@ cbuffer cb1
|
||||
float4 LODParams;
|
||||
float4 STRange;
|
||||
int4 ChannelShuffle;
|
||||
float2 ChannelShuffleOffset;
|
||||
float2 TC_OffsetHack;
|
||||
float2 STScale;
|
||||
float4x4 DitherMatrix;
|
||||
@@ -740,7 +741,7 @@ float4 fog(float4 c, float f)
|
||||
{
|
||||
if(PS_FOG)
|
||||
{
|
||||
c.rgb = trunc(lerp(FogColor, c.rgb, f));
|
||||
c.rgb = trunc(lerp(FogColor, c.rgb, (f * 255.0f) / 256.0f));
|
||||
}
|
||||
|
||||
return c;
|
||||
@@ -757,17 +758,17 @@ float4 ps_color(PS_INPUT input)
|
||||
#endif
|
||||
|
||||
#if PS_CHANNEL_FETCH == 1
|
||||
float4 T = fetch_red(int2(input.p.xy));
|
||||
float4 T = fetch_red(int2(input.p.xy + ChannelShuffleOffset));
|
||||
#elif PS_CHANNEL_FETCH == 2
|
||||
float4 T = fetch_green(int2(input.p.xy));
|
||||
float4 T = fetch_green(int2(input.p.xy + ChannelShuffleOffset));
|
||||
#elif PS_CHANNEL_FETCH == 3
|
||||
float4 T = fetch_blue(int2(input.p.xy));
|
||||
float4 T = fetch_blue(int2(input.p.xy + ChannelShuffleOffset));
|
||||
#elif PS_CHANNEL_FETCH == 4
|
||||
float4 T = fetch_alpha(int2(input.p.xy));
|
||||
float4 T = fetch_alpha(int2(input.p.xy + ChannelShuffleOffset));
|
||||
#elif PS_CHANNEL_FETCH == 5
|
||||
float4 T = fetch_rgb(int2(input.p.xy));
|
||||
float4 T = fetch_rgb(int2(input.p.xy + ChannelShuffleOffset));
|
||||
#elif PS_CHANNEL_FETCH == 6
|
||||
float4 T = fetch_gXbY(int2(input.p.xy));
|
||||
float4 T = fetch_gXbY(int2(input.p.xy + ChannelShuffleOffset));
|
||||
#elif PS_DEPTH_FMT > 0
|
||||
float4 T = sample_depth(st_int, input.p.xy);
|
||||
#else
|
||||
|
||||
@@ -49,6 +49,7 @@ layout(std140, binding = 0) uniform cb21
|
||||
vec4 STRange;
|
||||
|
||||
ivec4 ChannelShuffle;
|
||||
vec2 ChannelShuffleOffset;
|
||||
|
||||
vec2 TC_OffsetHack;
|
||||
vec2 STScale;
|
||||
@@ -315,7 +316,7 @@ int fetch_raw_depth()
|
||||
#if PS_TEX_IS_FB == 1
|
||||
return int(sample_from_rt().r * multiplier);
|
||||
#else
|
||||
return int(texelFetch(TextureSampler, ivec2(gl_FragCoord.xy), 0).r * multiplier);
|
||||
return int(texelFetch(TextureSampler, ivec2(gl_FragCoord.xy + ChannelShuffleOffset), 0).r * multiplier);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -324,7 +325,7 @@ vec4 fetch_raw_color()
|
||||
#if PS_TEX_IS_FB == 1
|
||||
return sample_from_rt();
|
||||
#else
|
||||
return texelFetch(TextureSampler, ivec2(gl_FragCoord.xy), 0);
|
||||
return texelFetch(TextureSampler, ivec2(gl_FragCoord.xy + ChannelShuffleOffset), 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -646,7 +647,7 @@ bool atst(vec4 C)
|
||||
void fog(inout vec4 C, float f)
|
||||
{
|
||||
#if PS_FOG != 0
|
||||
C.rgb = trunc(mix(FogColor, C.rgb, f));
|
||||
C.rgb = trunc(mix(FogColor, C.rgb, (f * 255.0f) / 256.0f));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -316,6 +316,7 @@ layout(std140, set = 0, binding = 1) uniform cb1
|
||||
vec4 LODParams;
|
||||
vec4 STRange;
|
||||
ivec4 ChannelShuffle;
|
||||
vec2 ChannelShuffleOffset;
|
||||
vec2 TC_OffsetHack;
|
||||
vec2 STScale;
|
||||
mat4 DitherMatrix;
|
||||
@@ -907,7 +908,7 @@ bool atst(vec4 C)
|
||||
vec4 fog(vec4 c, float f)
|
||||
{
|
||||
#if PS_FOG
|
||||
c.rgb = trunc(mix(FogColor, c.rgb, f));
|
||||
c.rgb = trunc(mix(FogColor, c.rgb, (f * 255.0f) / 256.0f));
|
||||
#endif
|
||||
|
||||
return c;
|
||||
@@ -926,17 +927,17 @@ vec4 ps_color()
|
||||
#if !NEEDS_TEX
|
||||
vec4 T = vec4(0.0f);
|
||||
#elif PS_CHANNEL_FETCH == 1
|
||||
vec4 T = fetch_red(ivec2(gl_FragCoord.xy));
|
||||
vec4 T = fetch_red(ivec2(gl_FragCoord.xy + ChannelShuffleOffset));
|
||||
#elif PS_CHANNEL_FETCH == 2
|
||||
vec4 T = fetch_green(ivec2(gl_FragCoord.xy));
|
||||
vec4 T = fetch_green(ivec2(gl_FragCoord.xy + ChannelShuffleOffset));
|
||||
#elif PS_CHANNEL_FETCH == 3
|
||||
vec4 T = fetch_blue(ivec2(gl_FragCoord.xy));
|
||||
vec4 T = fetch_blue(ivec2(gl_FragCoord.xy + ChannelShuffleOffset));
|
||||
#elif PS_CHANNEL_FETCH == 4
|
||||
vec4 T = fetch_alpha(ivec2(gl_FragCoord.xy));
|
||||
vec4 T = fetch_alpha(ivec2(gl_FragCoord.xy + ChannelShuffleOffset));
|
||||
#elif PS_CHANNEL_FETCH == 5
|
||||
vec4 T = fetch_rgb(ivec2(gl_FragCoord.xy));
|
||||
vec4 T = fetch_rgb(ivec2(gl_FragCoord.xy + ChannelShuffleOffset));
|
||||
#elif PS_CHANNEL_FETCH == 6
|
||||
vec4 T = fetch_gXbY(ivec2(gl_FragCoord.xy));
|
||||
vec4 T = fetch_gXbY(ivec2(gl_FragCoord.xy + ChannelShuffleOffset));
|
||||
#elif PS_DEPTH_FMT > 0
|
||||
vec4 T = sample_depth(st_int, ivec2(gl_FragCoord.xy));
|
||||
#else
|
||||
|
||||
@@ -110,8 +110,10 @@ disable_compiler_warnings_for_target(speex)
|
||||
if(ENABLE_QT_UI)
|
||||
find_package(Qt6 6.10.0 COMPONENTS CoreTools Core GuiTools Gui WidgetsTools Widgets LinguistTools REQUIRED)
|
||||
|
||||
if (Qt6_VERSION VERSION_GREATER_EQUAL 6.10.0)
|
||||
find_package(Qt6 COMPONENTS CorePrivate GuiPrivate WidgetsPrivate REQUIRED)
|
||||
if(NOT WIN32 AND NOT APPLE)
|
||||
if (Qt6_VERSION VERSION_GREATER_EQUAL 6.10.0)
|
||||
find_package(Qt6 COMPONENTS CorePrivate GuiPrivate WidgetsPrivate REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# The docking system for the debugger.
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
<DepsDLLs Include="$(DepsBinDir)plutovg.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)plutosvg.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AgilityDLLs Condition="Exists('$(DepsBinDir)D3D12\D3D12Core.dll')" Include="$(DepsBinDir)D3D12\D3D12Core.dll" />
|
||||
<AgilityDLLs Condition="Exists('$(DepsBinDir)D3D12\d3d12SDKLayers.dll')" Include="$(DepsBinDir)D3D12\d3d12SDKLayers.dll" />
|
||||
</ItemGroup>
|
||||
<Target Name="DepsListPDBs"
|
||||
AfterTargets="Build">
|
||||
<ItemGroup>
|
||||
@@ -56,4 +60,15 @@
|
||||
SkipUnchangedFiles="true"
|
||||
/>
|
||||
</Target>
|
||||
<Target Name="DepsCopyAgilityDLLs"
|
||||
AfterTargets="Build"
|
||||
Inputs="@(AgilityDLLs)"
|
||||
Outputs="@(AgilityDLLs -> '$(OutDir)D3D12\%(RecursiveDir)%(Filename)%(Extension)')">
|
||||
<Message Text="Copying Agility SDK DLLs" Importance="High" />
|
||||
<Copy
|
||||
SourceFiles="@(AgilityDLLs)"
|
||||
DestinationFolder="$(OutDir)D3D12"
|
||||
SkipUnchangedFiles="true"
|
||||
/>
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -289,11 +289,14 @@ target_link_libraries(pcsx2-qt PRIVATE
|
||||
PCSX2
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::GuiPrivate
|
||||
Qt6::Widgets
|
||||
KDAB::kddockwidgets
|
||||
)
|
||||
|
||||
if(NOT WIN32 AND NOT APPLE)
|
||||
target_link_libraries(pcsx2-qt PRIVATE Qt6::GuiPrivate)
|
||||
endif()
|
||||
|
||||
# Our Qt builds may have exceptions on, so force them off.
|
||||
target_compile_definitions(pcsx2-qt PRIVATE QT_NO_EXCEPTIONS)
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "common/RedtapeWindows.h"
|
||||
#elif !defined(APPLE)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
|
||||
DisplaySurface::DisplaySurface()
|
||||
@@ -477,6 +475,13 @@ bool DisplaySurface::eventFilter(QObject* object, QEvent* event)
|
||||
}
|
||||
return false;
|
||||
|
||||
case QEvent::FocusIn:
|
||||
// macOS: When we (the display window) get focus from another window with a toolbar we update to the MainWindow toolbar.
|
||||
// This is because we are a different native window from our MainWindow. So, whenever we get focus, focus our MainWindow.
|
||||
// That way macOS will show the MainWindow toolbar when you click from the debugger / log window to the game.
|
||||
if (auto* w = qobject_cast<QWidget*>(object))
|
||||
w->window()->activateWindow();
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -67,17 +67,6 @@ struct KeyCodeName
|
||||
const char* icon_name;
|
||||
};
|
||||
|
||||
// Extended keys for left/right versions, Non conflicting with Qt::Key enum
|
||||
enum ExtendedKeys
|
||||
{
|
||||
Key_RightShift = 0x01100022,
|
||||
Key_LeftShift = 0x01100023,
|
||||
Key_RightControl = 0x01100024,
|
||||
Key_LeftControl = 0x01100025,
|
||||
Key_RightAlt = 0x01100026,
|
||||
Key_LeftAlt = 0x01100027,
|
||||
};
|
||||
|
||||
static constexpr const KeyCodeName s_qt_key_names[] = {
|
||||
{Qt::Key_Escape, "Escape", ICON_PF_ESC},
|
||||
{Qt::Key_Tab, "Tab", ICON_PF_TAB},
|
||||
@@ -103,13 +92,6 @@ static constexpr const KeyCodeName s_qt_key_names[] = {
|
||||
{Qt::Key_Control, "Control", ICON_PF_CTRL},
|
||||
{Qt::Key_Meta, "Meta", ICON_PF_SUPER},
|
||||
{Qt::Key_Alt, "Alt", ICON_PF_ALT},
|
||||
// patch for left and right versions of the keys
|
||||
{ExtendedKeys::Key_LeftShift, "LShift", ICON_PF_SHIFT},
|
||||
{ExtendedKeys::Key_RightShift, "RShift", ICON_PF_SHIFT},
|
||||
{ExtendedKeys::Key_LeftControl, "LCtrl", ICON_PF_CTRL},
|
||||
{ExtendedKeys::Key_RightControl, "RCtrl", ICON_PF_CTRL},
|
||||
{ExtendedKeys::Key_LeftAlt, "LAlt", ICON_PF_ALT},
|
||||
{ExtendedKeys::Key_RightAlt, "RAlt", ICON_PF_ALT},
|
||||
{Qt::Key_CapsLock, "CapsLock", ICON_PF_CAPS},
|
||||
{Qt::Key_NumLock, "NumLock", ICON_PF_NUMLOCK},
|
||||
{Qt::Key_ScrollLock, "ScrollLock", ICON_PF_SCRLK},
|
||||
@@ -593,41 +575,6 @@ u32 QtUtils::KeyEventToCode(const QKeyEvent* ev)
|
||||
const u8 keycode = set_keycode ? map_text_to_keycode(text) : 0;
|
||||
int key = ev->key();
|
||||
|
||||
if (key == Qt::Key_Shift || key == Qt::Key_Alt || key == Qt::Key_Control)
|
||||
{
|
||||
#if defined(Q_OS_WIN) or defined(Q_OS_LINUX)
|
||||
// Scan codes (Tested it)
|
||||
// 0x2A : Left shift
|
||||
// 0x36 : Right shift
|
||||
// 0x1D : Left ctrl
|
||||
// 0xE01D : Right ctrl
|
||||
// 0x38 : Left alt
|
||||
// right alt can become ctrl + right alt in some keyboard layouts (windows)
|
||||
// but thats fine for our use case
|
||||
switch (ev->nativeScanCode())
|
||||
{
|
||||
case 0x2A:
|
||||
key = ExtendedKeys::Key_LeftShift;
|
||||
break;
|
||||
case 0x36:
|
||||
key = ExtendedKeys::Key_RightShift;
|
||||
break;
|
||||
case 0x1D:
|
||||
key = ExtendedKeys::Key_LeftControl;
|
||||
break;
|
||||
case 0xE01D:
|
||||
key = ExtendedKeys::Key_RightControl;
|
||||
break;
|
||||
case 0x38:
|
||||
key = ExtendedKeys::Key_LeftAlt;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
if (keycode != 0)
|
||||
key = keycode; // Override key if mapped
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ MemoryCardSettingsWidget::MemoryCardSettingsWidget(SettingsWindow* settings_dial
|
||||
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.directory, m_ui.browse, m_ui.open, m_ui.reset, "Folders",
|
||||
"MemoryCards", Path::Combine(EmuFolders::DataRoot, "memcards"));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.automaticManagement, "EmuCore", "McdFolderAutoManage", true);
|
||||
|
||||
setupAdditionalUi();
|
||||
|
||||
@@ -58,11 +57,6 @@ MemoryCardSettingsWidget::MemoryCardSettingsWidget(SettingsWindow* settings_dial
|
||||
connect(m_ui.deleteCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::deleteCard);
|
||||
|
||||
refresh();
|
||||
|
||||
dialog()->registerWidgetHelp(m_ui.automaticManagement, tr("Automatically manage saves based on running game"),
|
||||
tr("Checked"),
|
||||
tr("(Folder type only / Card size: Auto) Loads only the relevant booted game saves, ignoring others. Avoids "
|
||||
"running out of space for saves."));
|
||||
}
|
||||
|
||||
MemoryCardSettingsWidget::~MemoryCardSettingsWidget() = default;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <QtWidgets/QTreeWidget>
|
||||
#include <QtWidgets/QToolButton>
|
||||
#include <QtWidgets/QListWidget>
|
||||
#include <QtWidgets/QCheckBox>
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
||||
@@ -175,22 +175,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="settingsGroupBox">
|
||||
<property name="title">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="automaticManagement">
|
||||
<property name="text">
|
||||
<string>Automatically manage saves based on running game</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
@@ -211,7 +195,6 @@
|
||||
<tabstop>renameCard</tabstop>
|
||||
<tabstop>convertCard</tabstop>
|
||||
<tabstop>deleteCard</tabstop>
|
||||
<tabstop>automaticManagement</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -11888,12 +11888,12 @@ This action cannot be undone.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="2772"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="2713"/>
|
||||
<source>Stencil buffers and texture barriers are both unavailable, this will break some graphical effects.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="5114"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="5055"/>
|
||||
<source>Spin GPU During Readbacks is enabled, but calibrated timestamps are unavailable. This might be really slow.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -11995,7 +11995,7 @@ Please see our official documentation for more information.</source>
|
||||
<context>
|
||||
<name>GSDeviceVK</name>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="2137"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="2078"/>
|
||||
<source>Your GPU does not support the required Vulkan features.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
||||
@@ -1308,6 +1308,12 @@ function(setup_main_executable target)
|
||||
install(FILES "${DEPS_BINDIR}/${SYMBOL_TO_COPY}" DESTINATION "${CMAKE_SOURCE_DIR}/bin" OPTIONAL)
|
||||
endforeach()
|
||||
|
||||
set(AGILITY_DIR "${CMAKE_SOURCE_DIR}/deps/bin/D3D12")
|
||||
set(AGILITY_DEPS_TO_COPY D3D12Core.dll d3d12SDKLayers.dll)
|
||||
foreach(AGILITY_DEP_TO_COPY ${AGILITY_DEPS_TO_COPY})
|
||||
install(FILES "${DEPS_BINDIR}/D3D12/${AGILITY_DEP_TO_COPY}" DESTINATION "${CMAKE_SOURCE_DIR}/bin/D3D12" OPTIONAL)
|
||||
endforeach()
|
||||
|
||||
get_target_property(WINDEPLOYQT_EXE Qt6::windeployqt IMPORTED_LOCATION)
|
||||
install(CODE "execute_process(COMMAND \"${WINDEPLOYQT_EXE}\" \"${CMAKE_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${target}>\" --plugindir \"${CMAKE_SOURCE_DIR}/bin/QtPlugins\" --pdb --no-compiler-runtime --no-system-d3d-compiler --no-system-dxc-compiler --no-translations COMMAND_ERROR_IS_FATAL ANY)")
|
||||
install(CODE "file(WRITE \"${CMAKE_SOURCE_DIR}/bin/qt.conf\" \"[Paths]\\nPlugins = ./QtPlugins\")")
|
||||
|
||||
@@ -1326,7 +1326,6 @@ struct Pcsx2Config
|
||||
UseSavestateSelector : 1,
|
||||
InhibitScreensaver : 1,
|
||||
BackupSavestate : 1,
|
||||
McdFolderAutoManage : 1,
|
||||
ManuallySetRealTimeClock : 1, // passes user-set real-time clock information to cdvd at startup
|
||||
UseSystemLocaleFormat : 1, // presents OS time format instead of yyyy-MM-dd HH:mm:ss for manual RTC
|
||||
|
||||
|
||||
1275
pcsx2/GS/GSState.cpp
1275
pcsx2/GS/GSState.cpp
File diff suppressed because it is too large
Load Diff
@@ -127,37 +127,41 @@ private:
|
||||
|
||||
protected:
|
||||
static constexpr int INVALID_ALPHA_MINMAX = 500;
|
||||
static constexpr int MAX_DRAW_BUFFERS = 3;
|
||||
|
||||
GSVertex m_v = {};
|
||||
float m_q = 1.0f;
|
||||
GSVector4i m_scissor_cull_min = {};
|
||||
GSVector4i m_scissor_cull_max = {};
|
||||
GSVector4i m_xyof = {};
|
||||
u32 m_used_buffers_idx = 0;
|
||||
u32 m_current_buffer_idx = 0;
|
||||
bool m_recent_buffer_switch = false;
|
||||
|
||||
struct
|
||||
struct GSVertexBuff
|
||||
{
|
||||
GSVertex* buff;
|
||||
GSVertex* buff_copy; // same size buffer to copy/modify the original buffer
|
||||
GSVertex* buff_copy; // same size buffer to copy/modify the original buffer
|
||||
u32 head, tail, next, maxcount; // head: first vertex, tail: last vertex + 1, next: last indexed + 1
|
||||
u32 xy_tail;
|
||||
GSVector4i xy[4];
|
||||
GSVector4i xyhead;
|
||||
} m_vertex = {};
|
||||
};
|
||||
|
||||
struct
|
||||
GSVertexBuff m_vertex_buffers[MAX_DRAW_BUFFERS];
|
||||
GSVertexBuff* m_vertex;
|
||||
|
||||
struct GSIndexBuff
|
||||
{
|
||||
u16* buff;
|
||||
u32 tail;
|
||||
} m_index = {};
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
GSVertex* buff;
|
||||
u32 head, tail, next, maxcount; // head: first vertex, tail: last vertex + 1, next: last indexed + 1
|
||||
u32 xy_tail;
|
||||
GSVector4i xy[4];
|
||||
GSVector4i xyhead;
|
||||
} m_draw_vertex = {};
|
||||
GSIndexBuff m_index_buffers[MAX_DRAW_BUFFERS];
|
||||
|
||||
GSIndexBuff* m_index;
|
||||
|
||||
GSVertexBuff m_draw_vertex = {};
|
||||
|
||||
struct
|
||||
{
|
||||
@@ -165,6 +169,16 @@ protected:
|
||||
u32 tail;
|
||||
} m_draw_index = {};
|
||||
|
||||
struct GSDrawBufferEnv
|
||||
{
|
||||
GSDrawingEnvironment m_env;
|
||||
int m_backed_up_ctx = 0;
|
||||
u32 m_dirty_regs = 0;
|
||||
GSVector4i draw_rect = GSVector4i::zero();
|
||||
};
|
||||
|
||||
GSDrawBufferEnv m_env_buffers[MAX_DRAW_BUFFERS] = {};
|
||||
|
||||
void UpdateContext();
|
||||
void UpdateScissor();
|
||||
|
||||
@@ -175,6 +189,7 @@ protected:
|
||||
template<u32 prim> void HandleAutoFlush();
|
||||
bool EarlyDetectShuffle(u32 prim);
|
||||
void CheckCLUTValidity(u32 prim);
|
||||
bool CheckOverlapVerts(u32 n);
|
||||
|
||||
template <u32 prim, bool auto_flush> void VertexKick(u32 skip);
|
||||
|
||||
@@ -241,9 +256,10 @@ public:
|
||||
GSLocalMemory m_mem;
|
||||
GSDrawingEnvironment m_env = {};
|
||||
GSDrawingEnvironment m_prev_env = {};
|
||||
GSDrawingEnvironment m_temp_env = {};
|
||||
const GSDrawingEnvironment* m_draw_env = &m_env;
|
||||
GSDrawingContext* m_context = nullptr;
|
||||
GSVector4i temp_draw_rect = {};
|
||||
GSVector4i temp_draw_rect;
|
||||
std::unique_ptr<GSDumpBase> m_dump;
|
||||
bool m_scissor_invalid = false;
|
||||
bool m_quad_check_valid = false;
|
||||
@@ -258,7 +274,7 @@ public:
|
||||
bool m_using_temp_z = false;
|
||||
bool m_temp_z_full_copy = false;
|
||||
bool m_in_target_draw = false;
|
||||
bool m_channel_shuffle_abort = false;
|
||||
bool m_channel_shuffle_finish = false;
|
||||
|
||||
u32 m_target_offset = 0;
|
||||
u8 m_scanmask_used = 0;
|
||||
@@ -441,7 +457,15 @@ public:
|
||||
virtual void Reset(bool hardware_reset);
|
||||
virtual void UpdateSettings(const Pcsx2Config::GSOptions& old_config);
|
||||
|
||||
void ResetDrawBuffers();
|
||||
void ResetDrawBufferIdx();
|
||||
void FlushBuffers(bool use_flush_reason = false, GSFlushReason flush_reason = GSFlushReason::CONTEXTCHANGE);
|
||||
void PushBuffer();
|
||||
void SetDrawBufferEnv();
|
||||
void SetDrawBuffDirty();
|
||||
bool CanBufferNewDraw();
|
||||
void Flush(GSFlushReason reason);
|
||||
void FlushDraw(GSFlushReason reason);
|
||||
u32 CalcMask(int exp, int max_exp);
|
||||
void FlushPrim();
|
||||
bool TestDrawChanged();
|
||||
@@ -454,7 +478,7 @@ public:
|
||||
|
||||
virtual void Move();
|
||||
|
||||
GSVector4i GetTEX0Rect();
|
||||
GSVector4i GetTEX0Rect(GSDrawingContext prev_ctx);
|
||||
void CheckWriteOverlap(bool req_write, bool req_read);
|
||||
void Write(const u8* mem, int len);
|
||||
void Read(u8* mem, int len);
|
||||
|
||||
@@ -622,6 +622,7 @@ struct alignas(16) GSHWDrawConfig
|
||||
GSVector4 LODParams;
|
||||
GSVector4 STRange;
|
||||
GSVector4i ChannelShuffle;
|
||||
GSVector2 ChannelShuffleOffset;
|
||||
GSVector2 TCOffsetHack;
|
||||
GSVector2 STScale;
|
||||
|
||||
|
||||
@@ -426,7 +426,8 @@ GSRendererType D3D::GetPreferredRenderer()
|
||||
if (!feature_level.has_value())
|
||||
return GSRendererType::DX11;
|
||||
else if (feature_level == D3D_FEATURE_LEVEL_12_0)
|
||||
return check_vulkan_supported() ? GSRendererType::VK : GSRendererType::OGL;
|
||||
//return check_vulkan_supported() ? GSRendererType::VK : GSRendererType::OGL;
|
||||
return GSRendererType::DX12;
|
||||
else if (feature_level == D3D_FEATURE_LEVEL_11_0)
|
||||
return GSRendererType::OGL;
|
||||
else
|
||||
@@ -439,7 +440,8 @@ GSRendererType D3D::GetPreferredRenderer()
|
||||
if (!feature_level.has_value())
|
||||
return GSRendererType::DX11;
|
||||
else if (feature_level == D3D_FEATURE_LEVEL_12_0)
|
||||
return check_vulkan_supported() ? GSRendererType::VK : GSRendererType::DX12;
|
||||
//return check_vulkan_supported() ? GSRendererType::VK : GSRendererType::DX12;
|
||||
return GSRendererType::DX12;
|
||||
else if (feature_level == D3D_FEATURE_LEVEL_11_1)
|
||||
return GSRendererType::DX12;
|
||||
else
|
||||
|
||||
@@ -22,8 +22,8 @@ D3D12StreamBuffer::~D3D12StreamBuffer()
|
||||
|
||||
bool D3D12StreamBuffer::Create(u32 size)
|
||||
{
|
||||
const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN,
|
||||
{1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE};
|
||||
const GSDevice12::D3D12_RESOURCE_DESCU resource_desc = {{D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN,
|
||||
{1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}};
|
||||
|
||||
D3D12MA::ALLOCATION_DESC allocationDesc = {};
|
||||
allocationDesc.Flags = D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
@@ -31,8 +31,13 @@ bool D3D12StreamBuffer::Create(u32 size)
|
||||
|
||||
wil::com_ptr_nothrow<ID3D12Resource> buffer;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||
HRESULT hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource(&allocationDesc, &resource_desc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
|
||||
HRESULT hr;
|
||||
if (GSDevice12::GetInstance()->UseEnhancedBarriers())
|
||||
hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource3(&allocationDesc, &resource_desc.desc1,
|
||||
D3D12_BARRIER_LAYOUT_UNDEFINED, nullptr, 0, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
|
||||
else
|
||||
hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource(&allocationDesc, &resource_desc.desc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
|
||||
pxAssertMsg(SUCCEEDED(hr), "Allocate buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "common/ScopedGuard.h"
|
||||
#include "common/SmallString.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
|
||||
#include "D3D12MemAlloc.h"
|
||||
#include "imgui.h"
|
||||
@@ -158,6 +160,83 @@ u32 GSDevice12::GetAdapterVendorID() const
|
||||
return desc.VendorId;
|
||||
}
|
||||
|
||||
uint SDKVersion(const std::string& path)
|
||||
{
|
||||
// The Agility SDK version is embeded as the minor file version.
|
||||
// This is only true for the redist files, not the OS files.
|
||||
// Alternativly, D3D12Core also exports its D3D12SDKVersion.
|
||||
std::wstring wpath = FileSystem::GetWin32Path(path);
|
||||
|
||||
const DWORD size = GetFileVersionInfoSizeW(wpath.c_str(), nullptr);
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
BOOL ret;
|
||||
|
||||
std::vector<char> info_data(size);
|
||||
ret = GetFileVersionInfoW(wpath.c_str(), 0, size, info_data.data());
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
uint len;
|
||||
VS_FIXEDFILEINFO* file_ver;
|
||||
ret = VerQueryValueW(info_data.data(), L"\\", reinterpret_cast<void**>(&file_ver), &len);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
return file_ver->dwFileVersionMS & 0xFFFF;
|
||||
}
|
||||
|
||||
void GSDevice12::LoadAgilitySDK()
|
||||
{
|
||||
static bool agility_loaded = false;
|
||||
if (agility_loaded)
|
||||
return;
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// See https://microsoft.github.io/DirectX-Specs/d3d/IndependentDevices.html
|
||||
ComPtr<ID3D12SDKConfiguration1> sdk_configuration;
|
||||
hr = D3D12GetInterface(CLSID_D3D12SDKConfiguration, IID_PPV_ARGS(sdk_configuration.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("D3D12: Agility SDK configuration is not available");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string sdk_path = Path::Combine(Path::GetDirectory(FileSystem::GetProgramPath()), "\\D3D12\\");
|
||||
std::string core_path = Path::Combine(sdk_path, "D3D12Core.dll");
|
||||
if (!FileSystem::FileExists(core_path.c_str()))
|
||||
return;
|
||||
|
||||
const uint agility_version = SDKVersion(core_path);
|
||||
if (agility_version == 0)
|
||||
return;
|
||||
|
||||
ComPtr<ID3D12DeviceFactory> device_factory;
|
||||
// CreateDeviceFactory seems to use a utf8 string for the path.
|
||||
// If the system has a newer SDK, then the system SDK seems to be returned instead.
|
||||
hr = sdk_configuration->CreateDeviceFactory(agility_version,
|
||||
StringUtil::WideStringToUTF8String(FileSystem::GetWin32Path(sdk_path)).c_str(), IID_PPV_ARGS(device_factory.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.ErrorFmt("D3D12: Unable to load provided Agility SDK {:08X}", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Windows 10 (and older drivers on 11) will apply to the global state in ID3D12DeviceFactory::CreateDevice().
|
||||
// To get consistant behaviour across all systems, always apply the global state.
|
||||
// This also allows us to use the normal D3D12*() methods with the loaded agility SDK.
|
||||
hr = device_factory->ApplyToGlobalState();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.ErrorFmt("D3D12: Unable to apply provided Agility SDK {:08X}", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
agility_loaded = true;
|
||||
}
|
||||
|
||||
bool GSDevice12::CreateDevice(u32& vendor_id)
|
||||
{
|
||||
bool enable_debug_layer = GSConfig.UseDebugDevice;
|
||||
@@ -171,6 +250,9 @@ bool GSDevice12::CreateDevice(u32& vendor_id)
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// Load the Agility SDK
|
||||
LoadAgilitySDK();
|
||||
|
||||
// Enabling the debug layer will fail if the Graphics Tools feature is not installed.
|
||||
if (enable_debug_layer)
|
||||
{
|
||||
@@ -191,6 +273,7 @@ bool GSDevice12::CreateDevice(u32& vendor_id)
|
||||
// Intel Haswell doesn't actually support DX12 even tho the device is created which results in a crash,
|
||||
// to get around this check if device can be created using feature level 12 (skylake+).
|
||||
const bool isIntel = (vendor_id == 0x163C || vendor_id == 0x8086 || vendor_id == 0x8087);
|
||||
|
||||
// Create the actual device.
|
||||
hr = D3D12CreateDevice(m_adapter.get(), isIntel ? D3D_FEATURE_LEVEL_12_0 : D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
|
||||
if (FAILED(hr))
|
||||
@@ -206,6 +289,14 @@ bool GSDevice12::CreateDevice(u32& vendor_id)
|
||||
Console.Error("D3D12: Failed to get lookup adapter by device LUID");
|
||||
}
|
||||
|
||||
ComPtr<ID3D12DeviceConfiguration> config = m_device.try_query<ID3D12DeviceConfiguration>();
|
||||
int sdkVersion = 0;
|
||||
if (config)
|
||||
{
|
||||
sdkVersion = config->GetDesc().SDKVersion;
|
||||
Console.WriteLnFmt("D3D12: Agility version: {}", sdkVersion);
|
||||
}
|
||||
|
||||
if (enable_debug_layer)
|
||||
{
|
||||
ComPtr<ID3D12InfoQueue> info_queue = m_device.try_query<ID3D12InfoQueue>();
|
||||
@@ -218,14 +309,18 @@ bool GSDevice12::CreateDevice(u32& vendor_id)
|
||||
}
|
||||
|
||||
D3D12_INFO_QUEUE_FILTER filter = {};
|
||||
std::array<D3D12_MESSAGE_ID, 5> id_list{
|
||||
std::array<D3D12_MESSAGE_ID, 6> id_list{
|
||||
D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
|
||||
D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
|
||||
D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET,
|
||||
D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH,
|
||||
D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE,
|
||||
// The current OS version of D3D12 (616) has a validation bug
|
||||
// This is fixed with Agility 1.618.4.
|
||||
// For now, disable this warning untill the OS updates.
|
||||
D3D12_MESSAGE_ID_INCOMPATIBLE_BARRIER_LAYOUT,
|
||||
};
|
||||
filter.DenyList.NumIDs = static_cast<UINT>(id_list.size());
|
||||
filter.DenyList.NumIDs = static_cast<UINT>(sdkVersion < 618 ? id_list.size() : id_list.size() - 1);
|
||||
filter.DenyList.pIDList = id_list.data();
|
||||
info_queue->PushStorageFilter(&filter);
|
||||
}
|
||||
@@ -318,8 +413,17 @@ bool GSDevice12::CreateCommandLists()
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, res.command_allocators[i].get(),
|
||||
nullptr, IID_PPV_ARGS(res.command_lists[i].put()));
|
||||
if (m_enhanced_barriers)
|
||||
{
|
||||
hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, res.command_allocators[i].get(),
|
||||
nullptr, IID_PPV_ARGS(res.command_lists[i].list7.put()));
|
||||
res.command_lists[i].list4 = res.command_lists[i].list7;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, res.command_allocators[i].get(),
|
||||
nullptr, IID_PPV_ARGS(res.command_lists[i].list4.put()));
|
||||
}
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("D3D12: Failed to create command list: %08X", hr);
|
||||
@@ -327,7 +431,7 @@ bool GSDevice12::CreateCommandLists()
|
||||
}
|
||||
|
||||
// Close the command lists, since the first thing we do is reset them.
|
||||
hr = res.command_lists[i]->Close();
|
||||
hr = res.command_lists[i].list4->Close();
|
||||
pxAssertRel(SUCCEEDED(hr), "Closing new command list failed");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
@@ -365,7 +469,7 @@ void GSDevice12::MoveToNextCommandList()
|
||||
|
||||
// Begin command list.
|
||||
res.command_allocators[1]->Reset();
|
||||
res.command_lists[1]->Reset(res.command_allocators[1].get(), nullptr);
|
||||
res.command_lists[1].list4->Reset(res.command_allocators[1].get(), nullptr);
|
||||
res.descriptor_allocator.Reset();
|
||||
if (res.sampler_allocator.ShouldReset())
|
||||
res.sampler_allocator.Reset();
|
||||
@@ -397,18 +501,18 @@ void GSDevice12::MoveToNextCommandList()
|
||||
res.has_timestamp_query = m_gpu_timing_enabled;
|
||||
if (m_gpu_timing_enabled)
|
||||
{
|
||||
res.command_lists[1]->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
res.command_lists[1].list4->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST);
|
||||
}
|
||||
|
||||
ID3D12DescriptorHeap* heaps[2] = {
|
||||
res.descriptor_allocator.GetDescriptorHeap(), res.sampler_allocator.GetDescriptorHeap()};
|
||||
res.command_lists[1]->SetDescriptorHeaps(std::size(heaps), heaps);
|
||||
res.command_lists[1].list4->SetDescriptorHeaps(std::size(heaps), heaps);
|
||||
|
||||
m_allocator->SetCurrentFrameIndex(static_cast<UINT>(m_current_fence_value));
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList4* GSDevice12::GetInitCommandList()
|
||||
const D3D12CommandList& GSDevice12::GetInitCommandList()
|
||||
{
|
||||
CommandListResources& res = m_command_lists[m_current_command_list];
|
||||
if (!res.init_command_list_used)
|
||||
@@ -416,12 +520,12 @@ ID3D12GraphicsCommandList4* GSDevice12::GetInitCommandList()
|
||||
[[maybe_unused]] HRESULT hr = res.command_allocators[0]->Reset();
|
||||
pxAssertMsg(SUCCEEDED(hr), "Reset init command allocator failed");
|
||||
|
||||
res.command_lists[0]->Reset(res.command_allocators[0].get(), nullptr);
|
||||
res.command_lists[0].list4->Reset(res.command_allocators[0].get(), nullptr);
|
||||
pxAssertMsg(SUCCEEDED(hr), "Reset init command list failed");
|
||||
res.init_command_list_used = true;
|
||||
}
|
||||
|
||||
return res.command_lists[0].get();
|
||||
return res.command_lists[0];
|
||||
}
|
||||
|
||||
bool GSDevice12::ExecuteCommandList(WaitType wait_for_completion)
|
||||
@@ -432,16 +536,16 @@ bool GSDevice12::ExecuteCommandList(WaitType wait_for_completion)
|
||||
if (res.has_timestamp_query)
|
||||
{
|
||||
// write the timestamp back at the end of the cmdlist
|
||||
res.command_lists[1]->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
res.command_lists[1].list4->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
(m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST) + 1);
|
||||
res.command_lists[1]->ResolveQueryData(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
res.command_lists[1].list4->ResolveQueryData(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST, NUM_TIMESTAMP_QUERIES_PER_CMDLIST,
|
||||
m_timestamp_query_buffer.get(), m_current_command_list * (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST));
|
||||
}
|
||||
|
||||
if (res.init_command_list_used)
|
||||
{
|
||||
hr = res.command_lists[0]->Close();
|
||||
hr = res.command_lists[0].list4->Close();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("D3D12: Closing init command list failed with HRESULT %08X", hr);
|
||||
@@ -450,7 +554,7 @@ bool GSDevice12::ExecuteCommandList(WaitType wait_for_completion)
|
||||
}
|
||||
|
||||
// Close and queue command list.
|
||||
hr = res.command_lists[1]->Close();
|
||||
hr = res.command_lists[1].list4->Close();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("D3D12: Closing main command list failed with HRESULT %08X", hr);
|
||||
@@ -459,12 +563,12 @@ bool GSDevice12::ExecuteCommandList(WaitType wait_for_completion)
|
||||
|
||||
if (res.init_command_list_used)
|
||||
{
|
||||
const std::array<ID3D12CommandList*, 2> execute_lists{res.command_lists[0].get(), res.command_lists[1].get()};
|
||||
const std::array<ID3D12CommandList*, 2> execute_lists{res.command_lists[0].list4.get(), res.command_lists[1].list4.get()};
|
||||
m_command_queue->ExecuteCommandLists(static_cast<UINT>(execute_lists.size()), execute_lists.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::array<ID3D12CommandList*, 1> execute_lists{res.command_lists[1].get()};
|
||||
const std::array<ID3D12CommandList*, 1> execute_lists{res.command_lists[1].list4.get()};
|
||||
m_command_queue->ExecuteCommandLists(static_cast<UINT>(execute_lists.size()), execute_lists.data());
|
||||
}
|
||||
|
||||
@@ -598,10 +702,14 @@ bool GSDevice12::CreateTimestampQuery()
|
||||
}
|
||||
|
||||
const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_READBACK};
|
||||
const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, BUFFER_SIZE, 1, 1, 1,
|
||||
DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE};
|
||||
hr = m_allocator->CreateResource(&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
||||
m_timestamp_query_allocation.put(), IID_PPV_ARGS(m_timestamp_query_buffer.put()));
|
||||
const D3D12_RESOURCE_DESCU resource_desc = {{D3D12_RESOURCE_DIMENSION_BUFFER, 0, BUFFER_SIZE, 1, 1, 1,
|
||||
DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}};
|
||||
if (m_enhanced_barriers)
|
||||
hr = m_allocator->CreateResource3(&allocation_desc, &resource_desc.desc1, D3D12_BARRIER_LAYOUT_UNDEFINED, nullptr,
|
||||
0, nullptr, m_timestamp_query_allocation.put(), IID_PPV_ARGS(m_timestamp_query_buffer.put()));
|
||||
else
|
||||
hr = m_allocator->CreateResource(&allocation_desc, &resource_desc.desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
||||
m_timestamp_query_allocation.put(), IID_PPV_ARGS(m_timestamp_query_buffer.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("D3D12: CreateResource() for timestamp failed with %08X", hr);
|
||||
@@ -638,15 +746,20 @@ bool GSDevice12::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_
|
||||
{
|
||||
// Try to place the fixed index buffer in GPU local memory.
|
||||
// Use the staging buffer to copy into it.
|
||||
const D3D12_RESOURCE_DESC rd = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0},
|
||||
D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE};
|
||||
const D3D12_RESOURCE_DESCU rd = {{D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0},
|
||||
D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}};
|
||||
|
||||
const D3D12MA::ALLOCATION_DESC cpu_ad = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_UPLOAD};
|
||||
|
||||
ComPtr<ID3D12Resource> cpu_buffer;
|
||||
ComPtr<D3D12MA::Allocation> cpu_allocation;
|
||||
HRESULT hr = m_allocator->CreateResource(
|
||||
&cpu_ad, &rd, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, cpu_allocation.put(), IID_PPV_ARGS(cpu_buffer.put()));
|
||||
HRESULT hr;
|
||||
if (m_enhanced_barriers)
|
||||
hr = m_allocator->CreateResource3(
|
||||
&cpu_ad, &rd.desc1, D3D12_BARRIER_LAYOUT_UNDEFINED, nullptr, 0, nullptr, cpu_allocation.put(), IID_PPV_ARGS(cpu_buffer.put()));
|
||||
else
|
||||
hr = m_allocator->CreateResource(
|
||||
&cpu_ad, &rd.desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, cpu_allocation.put(), IID_PPV_ARGS(cpu_buffer.put()));
|
||||
pxAssertMsg(SUCCEEDED(hr), "Allocate CPU buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
@@ -662,21 +775,34 @@ bool GSDevice12::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_
|
||||
cpu_buffer->Unmap(0, &write_range);
|
||||
|
||||
const D3D12MA::ALLOCATION_DESC gpu_ad = {D3D12MA::ALLOCATION_FLAG_COMMITTED, D3D12_HEAP_TYPE_DEFAULT};
|
||||
|
||||
hr = m_allocator->CreateResource(
|
||||
&gpu_ad, &rd, D3D12_RESOURCE_STATE_COMMON, nullptr, gpu_allocation, IID_PPV_ARGS(gpu_buffer));
|
||||
if (m_enhanced_barriers)
|
||||
hr = m_allocator->CreateResource3(
|
||||
&gpu_ad, &rd.desc1, D3D12_BARRIER_LAYOUT_UNDEFINED, nullptr, 0, nullptr, gpu_allocation, IID_PPV_ARGS(gpu_buffer));
|
||||
else
|
||||
hr = m_allocator->CreateResource(
|
||||
&gpu_ad, &rd.desc, D3D12_RESOURCE_STATE_COMMON, nullptr, gpu_allocation, IID_PPV_ARGS(gpu_buffer));
|
||||
pxAssertMsg(SUCCEEDED(hr), "Allocate GPU buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
GetInitCommandList()->CopyBufferRegion(*gpu_buffer, 0, cpu_buffer.get(), 0, size);
|
||||
GetInitCommandList().list4->CopyBufferRegion(*gpu_buffer, 0, cpu_buffer.get(), 0, size);
|
||||
|
||||
D3D12_RESOURCE_BARRIER rb = {D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE};
|
||||
rb.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
rb.Transition.pResource = *gpu_buffer;
|
||||
rb.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; // COMMON -> COPY_DEST at first use.
|
||||
rb.Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
|
||||
GetInitCommandList()->ResourceBarrier(1, &rb);
|
||||
if (m_enhanced_barriers)
|
||||
{
|
||||
const D3D12_BUFFER_BARRIER barrier = {D3D12_BARRIER_SYNC_COPY, D3D12_BARRIER_SYNC_INDEX_INPUT,
|
||||
D3D12_BARRIER_ACCESS_COPY_DEST, D3D12_BARRIER_ACCESS_INDEX_BUFFER, *gpu_buffer, 0, size};
|
||||
const D3D12_BARRIER_GROUP group = {.Type = D3D12_BARRIER_TYPE_BUFFER, .NumBarriers = 1, .pBufferBarriers = &barrier};
|
||||
GetInitCommandList().list7->Barrier(1, &group);
|
||||
}
|
||||
else
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER rb = {D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE};
|
||||
rb.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
rb.Transition.pResource = *gpu_buffer;
|
||||
rb.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; // COMMON -> COPY_DEST at first use.
|
||||
rb.Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
|
||||
GetInitCommandList().list4->ResourceBarrier(1, &rb);
|
||||
}
|
||||
|
||||
DeferResourceDestruction(cpu_allocation.get(), cpu_buffer.get());
|
||||
return true;
|
||||
@@ -768,7 +894,7 @@ void GSDevice12::Destroy()
|
||||
{
|
||||
GSDevice::Destroy();
|
||||
|
||||
if (GetCommandList())
|
||||
if (GetCommandList().list4)
|
||||
{
|
||||
EndRenderPass();
|
||||
ExecuteCommandList(true);
|
||||
@@ -919,11 +1045,11 @@ bool GSDevice12::CreateSwapChain()
|
||||
// Render a frame as soon as possible to clear out whatever was previously being displayed.
|
||||
EndRenderPass();
|
||||
GSTexture12* swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer].get();
|
||||
ID3D12GraphicsCommandList4* cmdlist = GetCommandList();
|
||||
const D3D12CommandList& cmdlist = GetCommandList();
|
||||
m_current_swap_chain_buffer = ((m_current_swap_chain_buffer + 1) % static_cast<u32>(m_swap_chain_buffers.size()));
|
||||
swap_chain_buf->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
cmdlist->ClearRenderTargetView(swap_chain_buf->GetWriteDescriptor(), s_present_clear_color.data(), 0, nullptr);
|
||||
swap_chain_buf->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_PRESENT);
|
||||
swap_chain_buf->TransitionToState(cmdlist, GSTexture12::ResourceState::RenderTarget);
|
||||
cmdlist.list4->ClearRenderTargetView(swap_chain_buf->GetWriteDescriptor(), s_present_clear_color.data(), 0, nullptr);
|
||||
swap_chain_buf->TransitionToState(cmdlist, GSTexture12::ResourceState::Present);
|
||||
ExecuteCommandList(false);
|
||||
m_swap_chain->Present(0, m_using_allow_tearing ? DXGI_PRESENT_ALLOW_TEARING : 0);
|
||||
return true;
|
||||
@@ -950,7 +1076,7 @@ bool GSDevice12::CreateSwapChainRTV()
|
||||
std::unique_ptr<GSTexture12> tex = GSTexture12::Adopt(std::move(backbuffer), GSTexture::Type::RenderTarget,
|
||||
GSTexture::Format::Color, swap_chain_desc.BufferDesc.Width, swap_chain_desc.BufferDesc.Height, 1,
|
||||
swap_chain_desc.BufferDesc.Format, DXGI_FORMAT_UNKNOWN, swap_chain_desc.BufferDesc.Format,
|
||||
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_STATE_COMMON);
|
||||
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, GSTexture12::ResourceState::Present);
|
||||
if (!tex)
|
||||
{
|
||||
m_swap_chain_buffers.clear();
|
||||
@@ -1122,18 +1248,18 @@ GSDevice::PresentResult GSDevice12::BeginPresent(bool frame_skip)
|
||||
|
||||
GSTexture12* swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer].get();
|
||||
|
||||
ID3D12GraphicsCommandList* cmdlist = GetCommandList();
|
||||
swap_chain_buf->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
cmdlist->ClearRenderTargetView(swap_chain_buf->GetWriteDescriptor(), s_present_clear_color.data(), 0, nullptr);
|
||||
cmdlist->OMSetRenderTargets(1, &swap_chain_buf->GetWriteDescriptor().cpu_handle, FALSE, nullptr);
|
||||
const D3D12CommandList& cmdlist = GetCommandList();
|
||||
swap_chain_buf->TransitionToState(cmdlist, GSTexture12::ResourceState::RenderTarget);
|
||||
cmdlist.list4->ClearRenderTargetView(swap_chain_buf->GetWriteDescriptor(), s_present_clear_color.data(), 0, nullptr);
|
||||
cmdlist.list4->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};
|
||||
const D3D12_RECT scissor{
|
||||
0, 0, static_cast<LONG>(m_window_info.surface_width), static_cast<LONG>(m_window_info.surface_height)};
|
||||
cmdlist->RSSetViewports(1, &vp);
|
||||
cmdlist->RSSetScissorRects(1, &scissor);
|
||||
cmdlist.list4->RSSetViewports(1, &vp);
|
||||
cmdlist.list4->RSSetScissorRects(1, &scissor);
|
||||
return PresentResult::OK;
|
||||
}
|
||||
|
||||
@@ -1144,7 +1270,7 @@ void GSDevice12::EndPresent()
|
||||
GSTexture12* swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer].get();
|
||||
m_current_swap_chain_buffer = ((m_current_swap_chain_buffer + 1) % static_cast<u32>(m_swap_chain_buffers.size()));
|
||||
|
||||
swap_chain_buf->TransitionToState(GetCommandList(), D3D12_RESOURCE_STATE_PRESENT);
|
||||
swap_chain_buf->TransitionToState(GSTexture12::ResourceState::Present);
|
||||
if (!ExecuteCommandList(WaitType::None))
|
||||
{
|
||||
m_device_lost = true;
|
||||
@@ -1187,7 +1313,7 @@ void GSDevice12::PushDebugGroup(const char* fmt, ...)
|
||||
const UINT color = Palette(
|
||||
++s_debug_scope_depth, {0.5f, 0.5f, 0.5f}, {0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 0.5f}, {0.8f, 0.90f, 0.30f});
|
||||
|
||||
PIXBeginEvent(GetCommandList(), color, "%s", buf.c_str());
|
||||
PIXBeginEvent(GetCommandList().list4.get(), color, "%s", buf.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1199,7 +1325,7 @@ void GSDevice12::PopDebugGroup()
|
||||
|
||||
s_debug_scope_depth = (s_debug_scope_depth == 0) ? 0 : (s_debug_scope_depth - 1u);
|
||||
|
||||
PIXEndEvent(GetCommandList());
|
||||
PIXEndEvent(GetCommandList().list4.get());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1230,7 +1356,7 @@ void GSDevice12::InsertDebugMessage(DebugMessageCategory category, const char* f
|
||||
static_cast<BYTE>(fcolor[1] * 255.0f),
|
||||
static_cast<BYTE>(fcolor[2] * 255.0f));
|
||||
|
||||
PIXSetMarker(GetCommandList(), color, "%s", buf.c_str());
|
||||
PIXSetMarker(GetCommandList().list4.get(), color, "%s", buf.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1263,30 +1389,43 @@ bool GSDevice12::CheckFeatures(const u32& vendor_id)
|
||||
Console.WriteLnFmt("D3D12: Programmable Sample Position: {}", m_programmable_sample_positions ? "Supported" : "Not Supported");
|
||||
|
||||
BOOL allow_tearing_supported = false;
|
||||
const HRESULT hr = m_dxgi_factory->CheckFeatureSupport(
|
||||
HRESULT hr = m_dxgi_factory->CheckFeatureSupport(
|
||||
DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, sizeof(allow_tearing_supported));
|
||||
m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE);
|
||||
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS12 device_options12 = {};
|
||||
hr = m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &device_options12, sizeof(device_options12));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
Console.WriteLnFmt("D3D12: Enhanced Barriers: {}", device_options12.EnhancedBarriersSupported ? "Supported" : "Not Supported");
|
||||
m_enhanced_barriers = device_options12.EnhancedBarriersSupported;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLnFmt("D3D12: Failed to check for Enhanced Barriers: 0x{:08x}", static_cast<unsigned long>(hr));
|
||||
m_enhanced_barriers = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSDevice12::DrawPrimitive()
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
|
||||
GetCommandList()->DrawInstanced(m_vertex.count, 1, m_vertex.start, 0);
|
||||
GetCommandList().list4->DrawInstanced(m_vertex.count, 1, m_vertex.start, 0);
|
||||
}
|
||||
|
||||
void GSDevice12::DrawIndexedPrimitive()
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
|
||||
GetCommandList()->DrawIndexedInstanced(m_index.count, 1, m_index.start, m_vertex.start, 0);
|
||||
GetCommandList().list4->DrawIndexedInstanced(m_index.count, 1, m_index.start, m_vertex.start, 0);
|
||||
}
|
||||
|
||||
void GSDevice12::DrawIndexedPrimitive(int offset, int count)
|
||||
{
|
||||
pxAssert(offset + count <= (int)m_index.count);
|
||||
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
|
||||
GetCommandList()->DrawIndexedInstanced(count, 1, m_index.start + offset, m_vertex.start, 0);
|
||||
GetCommandList().list4->DrawIndexedInstanced(count, 1, m_index.start + offset, m_vertex.start, 0);
|
||||
}
|
||||
|
||||
void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_format, DXGI_FORMAT* srv_format,
|
||||
@@ -1391,14 +1530,14 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
|
||||
if (dTex12->GetType() != GSTexture::Type::DepthStencil)
|
||||
{
|
||||
dTex12->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
GetCommandList()->ClearRenderTargetView(
|
||||
dTex12->TransitionToState(GSTexture12::ResourceState::RenderTarget);
|
||||
GetCommandList().list4->ClearRenderTargetView(
|
||||
dTex12->GetWriteDescriptor(), sTex12->GetUNormClearColor().v, 0, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
dTex12->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
GetCommandList()->ClearDepthStencilView(
|
||||
dTex12->TransitionToState(GSTexture12::ResourceState::DepthWriteStencil);
|
||||
GetCommandList().list4->ClearDepthStencilView(
|
||||
dTex12->GetWriteDescriptor(), D3D12_CLEAR_FLAG_DEPTH, sTex12->GetClearDepth(), 0, 0, nullptr);
|
||||
}
|
||||
|
||||
@@ -1418,12 +1557,12 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
|
||||
EndRenderPass();
|
||||
|
||||
sTex12->TransitionToState(D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
sTex12->TransitionToState(GSTexture12::ResourceState::CopySrc);
|
||||
sTex12->SetUseFenceCounter(GetCurrentFenceValue());
|
||||
if (m_tfx_textures[0] && sTex12->GetSRVDescriptor() == m_tfx_textures[0])
|
||||
PSSetShaderResource(0, nullptr, false);
|
||||
|
||||
dTex12->TransitionToState(D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
dTex12->TransitionToState(GSTexture12::ResourceState::CopyDst);
|
||||
dTex12->SetUseFenceCounter(GetCurrentFenceValue());
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION srcloc;
|
||||
@@ -1440,13 +1579,13 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
const bool full_rt_copy = src_dst_rect_match && ((sTex12->IsDepthStencil() && !m_programmable_sample_positions) || (destX == 0 && destY == 0 && r.eq(src_rect)));
|
||||
if (full_rt_copy)
|
||||
{
|
||||
GetCommandList()->CopyResource(dTex12->GetResource(), sTex12->GetResource());
|
||||
GetCommandList().list4->CopyResource(dTex12->GetResource(), sTex12->GetResource());
|
||||
}
|
||||
else
|
||||
{
|
||||
const D3D12_BOX srcbox{static_cast<UINT>(r.left), static_cast<UINT>(r.top), 0u, static_cast<UINT>(r.right),
|
||||
static_cast<UINT>(r.bottom), 1u};
|
||||
GetCommandList()->CopyTextureRegion(&dstloc, destX, destY, 0, &srcloc, &srcbox);
|
||||
GetCommandList().list4->CopyTextureRegion(&dstloc, destX, destY, 0, &srcloc, &srcbox);
|
||||
}
|
||||
|
||||
dTex12->SetState(GSTexture::State::Dirty);
|
||||
@@ -1560,10 +1699,10 @@ void GSDevice12::DrawMultiStretchRects(
|
||||
{
|
||||
GSTexture12* const stex = static_cast<GSTexture12*>(rects[i].src);
|
||||
stex->CommitClear();
|
||||
if (stex->GetResourceState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)
|
||||
if (stex->GetResourceState() != GSTexture12::ResourceState::PixelShaderResource)
|
||||
{
|
||||
EndRenderPass();
|
||||
stex->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
stex->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1689,11 +1828,11 @@ void GSDevice12::BeginRenderPassForStretchRect(
|
||||
void GSDevice12::DoStretchRect(GSTexture12* sTex, const GSVector4& sRect, GSTexture12* dTex, const GSVector4& dRect,
|
||||
const ID3D12PipelineState* pipeline, bool linear, bool allow_discard)
|
||||
{
|
||||
if (sTex->GetResourceState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)
|
||||
if (sTex->GetResourceState() != GSTexture12::ResourceState::PixelShaderResource)
|
||||
{
|
||||
// can't transition in a render pass
|
||||
EndRenderPass();
|
||||
sTex->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
sTex->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
|
||||
SetUtilityRootSignature();
|
||||
@@ -1770,14 +1909,14 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
if (has_input_0)
|
||||
{
|
||||
static_cast<GSTexture12*>(sTex[0])->CommitClear();
|
||||
static_cast<GSTexture12*>(sTex[0])->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
static_cast<GSTexture12*>(sTex[0])->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
if (has_input_1)
|
||||
{
|
||||
static_cast<GSTexture12*>(sTex[1])->CommitClear();
|
||||
static_cast<GSTexture12*>(sTex[1])->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
static_cast<GSTexture12*>(sTex[1])->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(GSTexture12::ResourceState::RenderTarget);
|
||||
|
||||
// Upload constant to select YUV algo, but skip constant buffer update if we don't need it
|
||||
if (feedback_write_2 || feedback_write_1 || sTex[0])
|
||||
@@ -1830,7 +1969,7 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
if (sTex[0] == sTex[2])
|
||||
{
|
||||
// need a barrier here because of the render pass
|
||||
static_cast<GSTexture12*>(sTex[2])->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
static_cast<GSTexture12*>(sTex[2])->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1877,13 +2016,13 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
|
||||
// this texture is going to get used as an input, so make sure we don't read undefined data
|
||||
static_cast<GSTexture12*>(dTex)->CommitClear();
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
|
||||
void GSDevice12::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb)
|
||||
{
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(GSTexture12::ResourceState::RenderTarget);
|
||||
|
||||
const GSVector4i rc = GSVector4i(dRect);
|
||||
const GSVector4i dtex_rc = dTex->GetRect();
|
||||
@@ -1899,7 +2038,7 @@ void GSDevice12::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
EndRenderPass();
|
||||
|
||||
// this texture is going to get used as an input, so make sure we don't read undefined data
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
|
||||
void GSDevice12::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4])
|
||||
@@ -1918,7 +2057,7 @@ void GSDevice12::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float para
|
||||
DrawStretchRect(sRect, GSVector4(dRect), dTex->GetSize());
|
||||
EndRenderPass();
|
||||
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
|
||||
void GSDevice12::DoFXAA(GSTexture* sTex, GSTexture* dTex)
|
||||
@@ -1936,7 +2075,7 @@ void GSDevice12::DoFXAA(GSTexture* sTex, GSTexture* dTex)
|
||||
DrawStretchRect(sRect, GSVector4(dRect), dTex->GetSize());
|
||||
EndRenderPass();
|
||||
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
static_cast<GSTexture12*>(dTex)->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
|
||||
bool GSDevice12::CompileCASPipelines()
|
||||
@@ -2100,7 +2239,7 @@ void GSDevice12::RenderImGui()
|
||||
D3D12DescriptorHandle handle = m_null_texture->GetSRVDescriptor();
|
||||
if (tex)
|
||||
{
|
||||
tex->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
tex->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
handle = tex->GetSRVDescriptor();
|
||||
}
|
||||
|
||||
@@ -2118,7 +2257,7 @@ void GSDevice12::RenderImGui()
|
||||
|
||||
if (ApplyUtilityState())
|
||||
{
|
||||
GetCommandList()->DrawIndexedInstanced(
|
||||
GetCommandList().list4->DrawIndexedInstanced(
|
||||
pcmd->ElemCount, 1, m_index.start + pcmd->IdxOffset, vertex_offset + pcmd->VtxOffset, 0);
|
||||
}
|
||||
}
|
||||
@@ -2147,23 +2286,23 @@ bool GSDevice12::DoCAS(
|
||||
}
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList* const cmdlist = GetCommandList();
|
||||
const D3D12_RESOURCE_STATES old_state = sTex12->GetResourceState();
|
||||
sTex12->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
|
||||
dTex12->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
const D3D12CommandList& cmdlist = GetCommandList();
|
||||
const GSTexture12::ResourceState old_state = sTex12->GetResourceState();
|
||||
sTex12->TransitionToState(cmdlist, GSTexture12::ResourceState::ComputeShaderResource);
|
||||
dTex12->TransitionToState(cmdlist, GSTexture12::ResourceState::CASShaderUAV);
|
||||
|
||||
cmdlist->SetComputeRootSignature(m_cas_root_signature.get());
|
||||
cmdlist->SetComputeRoot32BitConstants(
|
||||
cmdlist.list4->SetComputeRootSignature(m_cas_root_signature.get());
|
||||
cmdlist.list4->SetComputeRoot32BitConstants(
|
||||
CAS_ROOT_SIGNATURE_PARAM_PUSH_CONSTANTS, NUM_CAS_CONSTANTS, constants.data(), 0);
|
||||
cmdlist->SetComputeRootDescriptorTable(CAS_ROOT_SIGNATURE_PARAM_SRC_TEXTURE, sTexDH);
|
||||
cmdlist->SetComputeRootDescriptorTable(CAS_ROOT_SIGNATURE_PARAM_DST_TEXTURE, dTexDH);
|
||||
cmdlist->SetPipelineState(sharpen_only ? m_cas_sharpen_pipeline.get() : m_cas_upscale_pipeline.get());
|
||||
cmdlist.list4->SetComputeRootDescriptorTable(CAS_ROOT_SIGNATURE_PARAM_SRC_TEXTURE, sTexDH);
|
||||
cmdlist.list4->SetComputeRootDescriptorTable(CAS_ROOT_SIGNATURE_PARAM_DST_TEXTURE, dTexDH);
|
||||
cmdlist.list4->SetPipelineState(sharpen_only ? m_cas_sharpen_pipeline.get() : m_cas_upscale_pipeline.get());
|
||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
||||
|
||||
static const int threadGroupWorkRegionDim = 16;
|
||||
const int dispatchX = (dTex->GetWidth() + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
const int dispatchY = (dTex->GetHeight() + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
cmdlist->Dispatch(dispatchX, dispatchY, 1);
|
||||
cmdlist.list4->Dispatch(dispatchX, dispatchY, 1);
|
||||
|
||||
sTex12->TransitionToState(cmdlist, old_state);
|
||||
return true;
|
||||
@@ -2243,9 +2382,9 @@ void GSDevice12::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector
|
||||
if (!InRenderPass())
|
||||
{
|
||||
if (vkRt)
|
||||
vkRt->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
vkRt->TransitionToState(GSTexture12::ResourceState::RenderTarget);
|
||||
if (vkDs)
|
||||
vkDs->TransitionToState(depth_read ? (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) : D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
vkDs->TransitionToState(depth_read ? GSTexture12::ResourceState::DepthReadStencil : GSTexture12::ResourceState::DepthWriteStencil);
|
||||
}
|
||||
|
||||
// This is used to set/initialize the framebuffer for tfx rendering.
|
||||
@@ -2374,7 +2513,7 @@ bool GSDevice12::CreateNullTexture()
|
||||
if (!m_null_texture)
|
||||
return false;
|
||||
|
||||
m_null_texture->TransitionToState(GetCommandList(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
m_null_texture->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
D3D12::SetObjectName(m_null_texture->GetResource(), "Null texture");
|
||||
return true;
|
||||
}
|
||||
@@ -3153,7 +3292,7 @@ void GSDevice12::ExecuteCommandListAndRestartRenderPass(bool wait_for_completion
|
||||
if (was_in_render_pass)
|
||||
{
|
||||
// rebind everything except RT, because the RP does that for us
|
||||
ApplyBaseState(m_dirty_flags & ~DIRTY_FLAG_RENDER_TARGET, GetCommandList());
|
||||
ApplyBaseState(m_dirty_flags & ~DIRTY_FLAG_RENDER_TARGET, GetCommandList().list4.get());
|
||||
m_dirty_flags &= ~DIRTY_BASE_STATE;
|
||||
|
||||
// restart render pass
|
||||
@@ -3244,17 +3383,17 @@ void GSDevice12::PSSetShaderResource(int i, GSTexture* sr, bool check_state, boo
|
||||
GSTexture12* dtex = static_cast<GSTexture12*>(sr);
|
||||
if (check_state)
|
||||
{
|
||||
if (dtex->GetResourceState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE && InRenderPass())
|
||||
if (dtex->GetResourceState() != GSTexture12::ResourceState::PixelShaderResource && InRenderPass())
|
||||
{
|
||||
GL_INS("Ending render pass due to resource transition");
|
||||
EndRenderPass();
|
||||
}
|
||||
|
||||
dtex->CommitClear();
|
||||
dtex->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
dtex->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
dtex->SetUseFenceCounter(GetCurrentFenceValue());
|
||||
handle = feedback ? dtex->GetFBLDescriptor() : dtex->GetSRVDescriptor();
|
||||
handle = (feedback && !m_enhanced_barriers) ? dtex->GetFBLDescriptor() : dtex->GetSRVDescriptor();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3285,7 +3424,7 @@ void GSDevice12::SetUtilityRootSignature()
|
||||
|
||||
m_current_root_signature = RootSignature::Utility;
|
||||
m_dirty_flags |= DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE | DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE | DIRTY_FLAG_PIPELINE;
|
||||
GetCommandList()->SetGraphicsRootSignature(m_utility_root_signature.get());
|
||||
GetCommandList().list4->SetGraphicsRootSignature(m_utility_root_signature.get());
|
||||
}
|
||||
|
||||
void GSDevice12::SetUtilityTexture(GSTexture* dtex, const D3D12DescriptorHandle& sampler)
|
||||
@@ -3295,7 +3434,7 @@ void GSDevice12::SetUtilityTexture(GSTexture* dtex, const D3D12DescriptorHandle&
|
||||
{
|
||||
GSTexture12* d12tex = static_cast<GSTexture12*>(dtex);
|
||||
d12tex->CommitClear();
|
||||
d12tex->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
d12tex->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
d12tex->SetUseFenceCounter(GetCurrentFenceValue());
|
||||
handle = d12tex->GetSRVDescriptor();
|
||||
}
|
||||
@@ -3333,7 +3472,7 @@ void GSDevice12::SetUtilityTexture(GSTexture* dtex, const D3D12DescriptorHandle&
|
||||
|
||||
void GSDevice12::SetUtilityPushConstants(const void* data, u32 size)
|
||||
{
|
||||
GetCommandList()->SetGraphicsRoot32BitConstants(
|
||||
GetCommandList().list4->SetGraphicsRoot32BitConstants(
|
||||
UTILITY_ROOT_SIGNATURE_PARAM_PUSH_CONSTANTS, (size + 3) / sizeof(u32), data, 0);
|
||||
}
|
||||
|
||||
@@ -3396,13 +3535,13 @@ void GSDevice12::RenderTextureMipmap(
|
||||
}
|
||||
|
||||
// *now* we don't have to worry about running out of anything.
|
||||
ID3D12GraphicsCommandList* cmdlist = GetCommandList();
|
||||
if (texture->GetResourceState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)
|
||||
const D3D12CommandList& cmdlist = GetCommandList();
|
||||
if (texture->GetResourceState() != GSTexture12::ResourceState::PixelShaderResource)
|
||||
texture->TransitionSubresourceToState(
|
||||
cmdlist, src_level, texture->GetResourceState(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
if (texture->GetResourceState() != D3D12_RESOURCE_STATE_RENDER_TARGET)
|
||||
cmdlist, src_level, texture->GetResourceState(), GSTexture12::ResourceState::PixelShaderResource);
|
||||
if (texture->GetResourceState() != GSTexture12::ResourceState::RenderTarget)
|
||||
texture->TransitionSubresourceToState(
|
||||
cmdlist, dst_level, texture->GetResourceState(), D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
cmdlist, dst_level, texture->GetResourceState(), GSTexture12::ResourceState::RenderTarget);
|
||||
|
||||
// We set the state directly here.
|
||||
constexpr u32 MODIFIED_STATE = DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_RENDER_TARGET;
|
||||
@@ -3410,14 +3549,14 @@ void GSDevice12::RenderTextureMipmap(
|
||||
|
||||
// Using a render pass is probably a bit overkill.
|
||||
const D3D12_DISCARD_REGION discard_region = {0u, nullptr, dst_level, 1u};
|
||||
cmdlist->DiscardResource(texture->GetResource(), &discard_region);
|
||||
cmdlist->OMSetRenderTargets(1, &rtv_handle.cpu_handle, FALSE, nullptr);
|
||||
cmdlist.list4->DiscardResource(texture->GetResource(), &discard_region);
|
||||
cmdlist.list4->OMSetRenderTargets(1, &rtv_handle.cpu_handle, FALSE, nullptr);
|
||||
|
||||
const D3D12_VIEWPORT vp = {0.0f, 0.0f, static_cast<float>(dst_width), static_cast<float>(dst_height), 0.0f, 1.0f};
|
||||
cmdlist->RSSetViewports(1, &vp);
|
||||
cmdlist.list4->RSSetViewports(1, &vp);
|
||||
|
||||
const D3D12_RECT scissor = {0, 0, static_cast<LONG>(dst_width), static_cast<LONG>(dst_height)};
|
||||
cmdlist->RSSetScissorRects(1, &scissor);
|
||||
cmdlist.list4->RSSetScissorRects(1, &scissor);
|
||||
|
||||
SetUtilityRootSignature();
|
||||
SetPipeline(m_convert[static_cast<int>(ShaderConvert::COPY)].get());
|
||||
@@ -3425,12 +3564,12 @@ void GSDevice12::RenderTextureMipmap(
|
||||
GSVector4(0.0f, 0.0f, static_cast<float>(dst_width), static_cast<float>(dst_height)),
|
||||
GSVector2i(dst_width, dst_height));
|
||||
|
||||
if (texture->GetResourceState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)
|
||||
if (texture->GetResourceState() != GSTexture12::ResourceState::PixelShaderResource)
|
||||
texture->TransitionSubresourceToState(
|
||||
cmdlist, src_level, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, texture->GetResourceState());
|
||||
if (texture->GetResourceState() != D3D12_RESOURCE_STATE_RENDER_TARGET)
|
||||
cmdlist, src_level, GSTexture12::ResourceState::PixelShaderResource, texture->GetResourceState());
|
||||
if (texture->GetResourceState() != GSTexture12::ResourceState::RenderTarget)
|
||||
texture->TransitionSubresourceToState(
|
||||
cmdlist, dst_level, D3D12_RESOURCE_STATE_RENDER_TARGET, texture->GetResourceState());
|
||||
cmdlist, dst_level, GSTexture12::ResourceState::RenderTarget, texture->GetResourceState());
|
||||
|
||||
// Must destroy after current cmdlist.
|
||||
DeferDescriptorDestruction(m_descriptor_heap_manager, &srv_handle);
|
||||
@@ -3496,7 +3635,7 @@ void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_b
|
||||
}
|
||||
}
|
||||
|
||||
GetCommandList()->BeginRenderPass(m_current_render_target ? 1 : 0,
|
||||
GetCommandList().list4->BeginRenderPass(m_current_render_target ? 1 : 0,
|
||||
m_current_render_target ? &rt : nullptr, m_current_depth_target ? &ds : nullptr,
|
||||
(m_current_depth_target && m_current_depth_read_only) ? (D3D12_RENDER_PASS_FLAG_BIND_READ_ONLY_DEPTH) : D3D12_RENDER_PASS_FLAG_NONE);
|
||||
}
|
||||
@@ -3513,7 +3652,7 @@ void GSDevice12::EndRenderPass()
|
||||
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, 1);
|
||||
|
||||
GetCommandList()->EndRenderPass();
|
||||
GetCommandList().list4->EndRenderPass();
|
||||
}
|
||||
|
||||
void GSDevice12::SetViewport(const D3D12_VIEWPORT& viewport)
|
||||
@@ -3675,7 +3814,7 @@ bool GSDevice12::ApplyTFXState(bool already_execed)
|
||||
flags |= DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2;
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList* cmdlist = GetCommandList();
|
||||
ID3D12GraphicsCommandList* cmdlist = GetCommandList().list4.get();
|
||||
|
||||
if (m_current_root_signature != RootSignature::TFX)
|
||||
{
|
||||
@@ -3714,7 +3853,7 @@ bool GSDevice12::ApplyUtilityState(bool already_execed)
|
||||
u32 flags = m_dirty_flags;
|
||||
m_dirty_flags &= ~DIRTY_UTILITY_STATE;
|
||||
|
||||
ID3D12GraphicsCommandList* cmdlist = GetCommandList();
|
||||
ID3D12GraphicsCommandList* cmdlist = GetCommandList().list4.get();
|
||||
|
||||
if (m_current_root_signature != RootSignature::Utility)
|
||||
{
|
||||
@@ -3846,11 +3985,37 @@ GSTexture12* GSDevice12::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, Pipe
|
||||
config.alpha_second_pass.ps.date = 3;
|
||||
|
||||
// and bind the image to the primitive sampler
|
||||
image->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
image->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
PSSetShaderResource(3, image, false);
|
||||
return image;
|
||||
}
|
||||
|
||||
void GSDevice12::FeedbackBarrier(const GSTexture12* texture)
|
||||
{
|
||||
if (m_enhanced_barriers)
|
||||
{
|
||||
// Enhanced barriers allows for single resource feedback.
|
||||
const D3D12_BARRIER_SYNC sync = D3D12_BARRIER_SYNC_RENDER_TARGET | D3D12_BARRIER_SYNC_PIXEL_SHADING;
|
||||
const D3D12_BARRIER_ACCESS access = D3D12_BARRIER_ACCESS_RENDER_TARGET | D3D12_BARRIER_ACCESS_SHADER_RESOURCE;
|
||||
const D3D12_TEXTURE_BARRIER barrier = {sync, sync, access, access, D3D12_BARRIER_LAYOUT_COMMON, D3D12_BARRIER_LAYOUT_COMMON,
|
||||
texture->GetResource(), {D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, 0, 0, 0, 0, 0}, D3D12_TEXTURE_BARRIER_FLAG_NONE};
|
||||
const D3D12_BARRIER_GROUP group = {.Type = D3D12_BARRIER_TYPE_TEXTURE, .NumBarriers = 1, .pTextureBarriers = &barrier};
|
||||
GetCommandList().list7->Barrier(1, &group);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The DX12 spec notes "You may not read from, or consume, a write that occurred within the same render pass".
|
||||
// The only exception being the implicit reads for render target blending or depth testing.
|
||||
// Thus, in addition to a barrier, we need to end the render pass.
|
||||
EndRenderPass();
|
||||
// Specify null for the after resource as both resources are used after the barrier.
|
||||
// While this may also be true before the barrier, we only write using the main resource.
|
||||
D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_ALIASING, D3D12_RESOURCE_BARRIER_FLAG_NONE};
|
||||
barrier.Aliasing = {texture->GetResource(), nullptr};
|
||||
GetCommandList().list4->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
|
||||
@@ -3871,12 +4036,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
if (m_features.texture_barrier && config.tex && (config.tex == config.rt) && !(config.require_one_barrier || config.require_full_barrier))
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::Barriers, 1);
|
||||
|
||||
EndRenderPass();
|
||||
// Specify null for the after resource as both resources are used after the barrier.
|
||||
D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_ALIASING, D3D12_RESOURCE_BARRIER_FLAG_NONE};
|
||||
barrier.Aliasing = {draw_rt->GetResource(), nullptr};
|
||||
GetCommandList()->ResourceBarrier(1, &barrier);
|
||||
FeedbackBarrier(draw_rt);
|
||||
}
|
||||
|
||||
// now blit the colclip texture back to the original target
|
||||
@@ -3887,7 +4047,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
GL_PUSH("Blit ColorClip back to RT");
|
||||
|
||||
EndRenderPass();
|
||||
colclip_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
colclip_rt->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
|
||||
draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.colclip_update_area);
|
||||
@@ -4001,7 +4161,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
else if (draw_rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
GL_PUSH_("ColorClip Render Target Setup");
|
||||
draw_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
draw_rt->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
}
|
||||
|
||||
// we're not drawing to the RT, so we can use it as a source
|
||||
@@ -4064,10 +4224,10 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
EndRenderPass();
|
||||
// Make sure the DSV is in writeable state
|
||||
draw_ds->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
draw_ds->TransitionToState(GSTexture12::ResourceState::DepthWriteStencil);
|
||||
|
||||
D3D12_RECT rect = {config.drawarea.left, config.drawarea.top, config.drawarea.left + config.drawarea.width(), config.drawarea.top + config.drawarea.height()};
|
||||
GetCommandList()->ClearDepthStencilView(draw_ds->GetWriteDescriptor(), D3D12_CLEAR_FLAG_STENCIL, 0.0f, 1, 1, &rect);
|
||||
GetCommandList().list4->ClearDepthStencilView(draw_ds->GetWriteDescriptor(), D3D12_CLEAR_FLAG_STENCIL, 0.0f, 1, 1, &rect);
|
||||
}
|
||||
|
||||
// Begin render pass if new target or out of the area.
|
||||
@@ -4167,7 +4327,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
GL_PUSH("Blit ColorClip back to RT");
|
||||
|
||||
EndRenderPass();
|
||||
colclip_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
colclip_rt->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
|
||||
|
||||
draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.colclip_update_area);
|
||||
@@ -4223,12 +4383,7 @@ void GSDevice12::SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig&
|
||||
{
|
||||
const u32 count = (*config.drawlist)[n] * indices_per_prim;
|
||||
|
||||
EndRenderPass();
|
||||
// Specify null for the after resource as both resources are used after the barrier.
|
||||
// While this may also be true before the barrier, we only write using the main resource.
|
||||
D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_ALIASING, D3D12_RESOURCE_BARRIER_FLAG_NONE};
|
||||
barrier.Aliasing = {draw_rt->GetResource(), nullptr};
|
||||
GetCommandList()->ResourceBarrier(1, &barrier);
|
||||
FeedbackBarrier(draw_rt);
|
||||
|
||||
if (BindDrawPipeline(pipe))
|
||||
DrawIndexedPrimitive(p, count);
|
||||
@@ -4242,11 +4397,7 @@ void GSDevice12::SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig&
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::Barriers, 1);
|
||||
|
||||
EndRenderPass();
|
||||
// Specify null for the after resource as both resources are used after the barrier.
|
||||
D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_ALIASING, D3D12_RESOURCE_BARRIER_FLAG_NONE};
|
||||
barrier.Aliasing = {draw_rt->GetResource(), nullptr};
|
||||
GetCommandList()->ResourceBarrier(1, &barrier);
|
||||
FeedbackBarrier(draw_rt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,14 @@ namespace D3D12MA
|
||||
class Allocator;
|
||||
}
|
||||
|
||||
struct D3D12CommandList
|
||||
{
|
||||
// Main command list
|
||||
wil::com_ptr_nothrow<ID3D12GraphicsCommandList4> list4;
|
||||
// Enhanced barriers command list
|
||||
wil::com_ptr_nothrow<ID3D12GraphicsCommandList7> list7;
|
||||
};
|
||||
|
||||
class GSDevice12 final : public GSDevice
|
||||
{
|
||||
public:
|
||||
@@ -42,6 +50,12 @@ public:
|
||||
NUM_TIMESTAMP_QUERIES_PER_CMDLIST = 2,
|
||||
};
|
||||
|
||||
union D3D12_RESOURCE_DESCU
|
||||
{
|
||||
D3D12_RESOURCE_DESC1 desc1;
|
||||
D3D12_RESOURCE_DESC desc;
|
||||
};
|
||||
|
||||
__fi IDXGIAdapter1* GetAdapter() const { return m_adapter.get(); }
|
||||
__fi ID3D12Device* GetDevice() const { return m_device.get(); }
|
||||
__fi ID3D12CommandQueue* GetCommandQueue() const { return m_command_queue.get(); }
|
||||
@@ -50,14 +64,16 @@ public:
|
||||
/// Returns the PCI vendor ID of the device, if known.
|
||||
u32 GetAdapterVendorID() const;
|
||||
|
||||
bool UseEnhancedBarriers() const { return m_enhanced_barriers; }
|
||||
|
||||
/// Returns the current command list, commands can be recorded directly.
|
||||
ID3D12GraphicsCommandList4* GetCommandList() const
|
||||
const D3D12CommandList& GetCommandList() const
|
||||
{
|
||||
return m_command_lists[m_current_command_list].command_lists[1].get();
|
||||
return m_command_lists[m_current_command_list].command_lists[1];
|
||||
}
|
||||
|
||||
/// Returns the init command list for uploading.
|
||||
ID3D12GraphicsCommandList4* GetInitCommandList();
|
||||
const D3D12CommandList& GetInitCommandList();
|
||||
|
||||
/// Returns the per-frame SRV/CBV/UAV allocator.
|
||||
D3D12DescriptorAllocator& GetDescriptorAllocator()
|
||||
@@ -137,7 +153,7 @@ private:
|
||||
struct CommandListResources
|
||||
{
|
||||
std::array<ComPtr<ID3D12CommandAllocator>, 2> command_allocators;
|
||||
std::array<ComPtr<ID3D12GraphicsCommandList4>, 2> command_lists;
|
||||
std::array<D3D12CommandList, 2> command_lists;
|
||||
D3D12DescriptorAllocator descriptor_allocator;
|
||||
D3D12GroupedSamplerAllocator<SAMPLER_GROUP_SIZE> sampler_allocator;
|
||||
std::vector<std::pair<D3D12MA::Allocation*, ID3D12DeviceChild*>> pending_resources;
|
||||
@@ -147,6 +163,8 @@ private:
|
||||
bool has_timestamp_query = false;
|
||||
};
|
||||
|
||||
void LoadAgilitySDK();
|
||||
|
||||
bool CreateDevice(u32& vendor_id);
|
||||
bool CreateDescriptorHeaps();
|
||||
bool CreateCommandLists();
|
||||
@@ -296,6 +314,7 @@ private:
|
||||
bool m_allow_tearing_supported = false;
|
||||
bool m_using_allow_tearing = false;
|
||||
bool m_is_exclusive_fullscreen = false;
|
||||
bool m_enhanced_barriers = true;
|
||||
bool m_device_lost = false;
|
||||
|
||||
ComPtr<ID3D12RootSignature> m_tfx_root_signature;
|
||||
@@ -377,6 +396,8 @@ private:
|
||||
ComPtr<ID3DBlob> GetUtilityVertexShader(const std::string& source, const char* entry_point);
|
||||
ComPtr<ID3DBlob> GetUtilityPixelShader(const std::string& source, const char* entry_point);
|
||||
|
||||
void FeedbackBarrier(const GSTexture12* texture);
|
||||
|
||||
bool CheckFeatures(const u32& vendor_id);
|
||||
bool CreateNullTexture();
|
||||
bool CreateBuffers();
|
||||
|
||||
@@ -19,7 +19,7 @@ GSTexture12::GSTexture12(Type type, Format format, int width, int height, int le
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
|
||||
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& ro_dsv_descriptor,
|
||||
const D3D12DescriptorHandle& uav_descriptor, const D3D12DescriptorHandle& fbl_descriptor,
|
||||
WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state)
|
||||
WriteDescriptorType wdtype, bool simultaneous_texture, ResourceState resource_state)
|
||||
: m_resource(std::move(resource))
|
||||
, m_resource_fbl(std::move(resource_fbl))
|
||||
, m_allocation(std::move(allocation))
|
||||
@@ -31,6 +31,7 @@ GSTexture12::GSTexture12(Type type, Format format, int width, int height, int le
|
||||
, m_write_descriptor_type(wdtype)
|
||||
, m_dxgi_format(dxgi_format)
|
||||
, m_resource_state(resource_state)
|
||||
, m_simultaneous_tex(simultaneous_texture)
|
||||
{
|
||||
m_type = type;
|
||||
m_format = format;
|
||||
@@ -111,28 +112,87 @@ void GSTexture12::Destroy(bool defer)
|
||||
m_write_descriptor_type = WriteDescriptorType::None;
|
||||
}
|
||||
|
||||
// For use with non-simultaneous textures only.
|
||||
// Simultaneous testures are always D3D12_BARRIER_LAYOUT_COMMON.
|
||||
static D3D12_BARRIER_LAYOUT GetD3D12BarrierLayout(GSTexture12::ResourceState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case GSTexture12::ResourceState::Undefined:
|
||||
return D3D12_BARRIER_LAYOUT_UNDEFINED;
|
||||
case GSTexture12::ResourceState::Present:
|
||||
return D3D12_BARRIER_LAYOUT_COMMON;
|
||||
case GSTexture12::ResourceState::RenderTarget:
|
||||
return D3D12_BARRIER_LAYOUT_RENDER_TARGET;
|
||||
case GSTexture12::ResourceState::DepthWriteStencil:
|
||||
return D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE;
|
||||
case GSTexture12::ResourceState::PixelShaderResource:
|
||||
case GSTexture12::ResourceState::ComputeShaderResource:
|
||||
return D3D12_BARRIER_LAYOUT_SHADER_RESOURCE;
|
||||
case GSTexture12::ResourceState::CopySrc:
|
||||
return D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE;
|
||||
case GSTexture12::ResourceState::CopyDst:
|
||||
return D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_DEST;
|
||||
case GSTexture12::ResourceState::CASShaderUAV:
|
||||
case GSTexture12::ResourceState::PixelShaderUAV:
|
||||
return D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;
|
||||
default:
|
||||
pxAssert(false);
|
||||
return D3D12_BARRIER_LAYOUT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
static D3D12_RESOURCE_STATES GetD3D12ResourceState(GSTexture12::ResourceState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case GSTexture12::ResourceState::Undefined:
|
||||
return D3D12_RESOURCE_STATE_COMMON;
|
||||
case GSTexture12::ResourceState::Present:
|
||||
return D3D12_RESOURCE_STATE_COMMON;
|
||||
case GSTexture12::ResourceState::RenderTarget:
|
||||
return D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
case GSTexture12::ResourceState::DepthWriteStencil:
|
||||
return D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
||||
case GSTexture12::ResourceState::PixelShaderResource:
|
||||
return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
case GSTexture12::ResourceState::ComputeShaderResource:
|
||||
return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
case GSTexture12::ResourceState::CopySrc:
|
||||
return D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
case GSTexture12::ResourceState::CopyDst:
|
||||
return D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
case GSTexture12::ResourceState::CASShaderUAV:
|
||||
case GSTexture12::ResourceState::PixelShaderUAV:
|
||||
return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
default:
|
||||
pxAssert(false);
|
||||
return D3D12_RESOURCE_STATE_COMMON;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int width, int height, int levels,
|
||||
DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format,
|
||||
DXGI_FORMAT uav_format)
|
||||
{
|
||||
GSDevice12* const dev = GSDevice12::GetInstance();
|
||||
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
desc.DepthOrArraySize = 1;
|
||||
desc.MipLevels = levels;
|
||||
desc.Format = dxgi_format;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||
GSDevice12::D3D12_RESOURCE_DESCU desc = {};
|
||||
desc.desc1.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
desc.desc1.Width = width;
|
||||
desc.desc1.Height = height;
|
||||
desc.desc1.DepthOrArraySize = 1;
|
||||
desc.desc1.MipLevels = levels;
|
||||
desc.desc1.Format = dxgi_format;
|
||||
desc.desc1.SampleDesc.Count = 1;
|
||||
desc.desc1.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||
|
||||
D3D12MA::ALLOCATION_DESC allocationDesc = {};
|
||||
allocationDesc.Flags = D3D12MA::ALLOCATION_FLAG_WITHIN_BUDGET;
|
||||
allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
|
||||
|
||||
D3D12_CLEAR_VALUE optimized_clear_value = {};
|
||||
D3D12_RESOURCE_STATES state;
|
||||
ResourceState state;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@@ -140,9 +200,9 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
{
|
||||
// This is a little annoying. basically, to do mipmap generation, we need to be a render target.
|
||||
// If it's a compressed texture, we won't be generating mips anyway, so this should be fine.
|
||||
desc.Flags = (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET :
|
||||
D3D12_RESOURCE_FLAG_NONE;
|
||||
state = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
desc.desc1.Flags = (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET :
|
||||
D3D12_RESOURCE_FLAG_NONE;
|
||||
state = ResourceState::CopyDst;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -152,10 +212,11 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
pxAssert(levels == 1);
|
||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
allocationDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;
|
||||
desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
|
||||
desc.desc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;
|
||||
if (!dev->UseEnhancedBarriers())
|
||||
desc.desc1.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
|
||||
optimized_clear_value.Format = rtv_format;
|
||||
state = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
state = ResourceState::RenderTarget;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -163,9 +224,9 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
{
|
||||
pxAssert(levels == 1);
|
||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||
desc.desc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||
optimized_clear_value.Format = dsv_format;
|
||||
state = D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
||||
state = ResourceState::DepthWriteStencil;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -173,7 +234,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
{
|
||||
pxAssert(levels == 1);
|
||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
state = ResourceState::PixelShaderResource;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -182,15 +243,16 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
}
|
||||
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN)
|
||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource;
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource_fbl;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||
|
||||
if (type == Type::RenderTarget)
|
||||
if (type == Type::RenderTarget && !dev->UseEnhancedBarriers())
|
||||
{
|
||||
const D3D12_RESOURCE_ALLOCATION_INFO allocInfo = dev->GetDevice()->GetResourceAllocationInfo(0, 1, &desc);
|
||||
// We need to use an aliased resource for feedback with legacy barriers.
|
||||
const D3D12_RESOURCE_ALLOCATION_INFO allocInfo = dev->GetDevice()->GetResourceAllocationInfo(0, 1, &desc.desc);
|
||||
|
||||
HRESULT hr = dev->GetAllocator()->AllocateMemory(&allocationDesc, &allocInfo, allocation.put());
|
||||
if (FAILED(hr))
|
||||
@@ -202,7 +264,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
return {};
|
||||
}
|
||||
|
||||
hr = dev->GetAllocator()->CreateAliasingResource(allocation.get(), 0, &desc, state,
|
||||
hr = dev->GetAllocator()->CreateAliasingResource(allocation.get(), 0, &desc.desc, GetD3D12ResourceState(state),
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr,
|
||||
IID_PPV_ARGS(resource.put()));
|
||||
if (FAILED(hr))
|
||||
@@ -214,7 +276,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
return {};
|
||||
}
|
||||
|
||||
hr = dev->GetAllocator()->CreateAliasingResource(allocation.get(), 0, &desc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||
hr = dev->GetAllocator()->CreateAliasingResource(allocation.get(), 0, &desc.desc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr,
|
||||
IID_PPV_ARGS(resource_fbl.put()));
|
||||
if (FAILED(hr))
|
||||
@@ -228,9 +290,20 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
}
|
||||
else
|
||||
{
|
||||
HRESULT hr = dev->GetAllocator()->CreateResource(&allocationDesc, &desc, state,
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr, allocation.put(),
|
||||
IID_PPV_ARGS(resource.put()));
|
||||
HRESULT hr;
|
||||
if (dev->UseEnhancedBarriers())
|
||||
{
|
||||
hr = dev->GetAllocator()->CreateResource3(&allocationDesc, &desc.desc1,
|
||||
type == Type::RenderTarget ? D3D12_BARRIER_LAYOUT_COMMON : GetD3D12BarrierLayout(state),
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr,
|
||||
0, nullptr, allocation.put(), IID_PPV_ARGS(resource.put()));
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = dev->GetAllocator()->CreateResource(&allocationDesc, &desc.desc, GetD3D12ResourceState(state),
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr, allocation.put(),
|
||||
IID_PPV_ARGS(resource.put()));
|
||||
}
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// OOM isn't fatal.
|
||||
@@ -301,8 +374,10 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
return {};
|
||||
}
|
||||
|
||||
// Feedback descriptor used with legacy barriers
|
||||
if (resource_fbl)
|
||||
{
|
||||
pxAssert(!dev->UseEnhancedBarriers());
|
||||
if (!CreateSRVDescriptor(resource_fbl.get(), levels, srv_format, &fbl_descriptor))
|
||||
{
|
||||
dev->GetDescriptorHeapManager().Free(&uav_descriptor);
|
||||
@@ -325,12 +400,12 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
|
||||
return std::unique_ptr<GSTexture12>(
|
||||
new GSTexture12(type, format, width, height, levels, dxgi_format, std::move(resource), std::move(resource_fbl), std::move(allocation),
|
||||
srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, state));
|
||||
srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, type == Type::RenderTarget, state));
|
||||
}
|
||||
|
||||
std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resource> resource, Type type, Format format,
|
||||
int width, int height, int levels, DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format,
|
||||
DXGI_FORMAT dsv_format, DXGI_FORMAT uav_format, D3D12_RESOURCE_STATES resource_state)
|
||||
DXGI_FORMAT dsv_format, DXGI_FORMAT uav_format, ResourceState resource_state)
|
||||
{
|
||||
const D3D12_RESOURCE_DESC desc = resource->GetDesc();
|
||||
|
||||
@@ -391,7 +466,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
||||
|
||||
return std::unique_ptr<GSTexture12>(new GSTexture12(type, format, static_cast<u32>(desc.Width), desc.Height,
|
||||
desc.MipLevels, desc.Format, std::move(resource), {}, {}, srv_descriptor, write_descriptor, {}, uav_descriptor,
|
||||
{}, write_descriptor_type, resource_state));
|
||||
{}, write_descriptor_type, false, resource_state));
|
||||
}
|
||||
|
||||
bool GSTexture12::CreateSRVDescriptor(
|
||||
@@ -432,7 +507,7 @@ bool GSTexture12::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT form
|
||||
return false;
|
||||
}
|
||||
|
||||
const D3D12_DEPTH_STENCIL_VIEW_DESC desc = {format, D3D12_DSV_DIMENSION_TEXTURE2D, read_only ? D3D12_DSV_FLAG_READ_ONLY_DEPTH : D3D12_DSV_FLAG_NONE };
|
||||
const D3D12_DEPTH_STENCIL_VIEW_DESC desc = {format, D3D12_DSV_DIMENSION_TEXTURE2D, read_only ? D3D12_DSV_FLAG_READ_ONLY_DEPTH : D3D12_DSV_FLAG_NONE};
|
||||
GSDevice12::GetInstance()->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle);
|
||||
return true;
|
||||
}
|
||||
@@ -455,7 +530,7 @@ void* GSTexture12::GetNativeHandle() const
|
||||
return const_cast<GSTexture12*>(this);
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList* GSTexture12::GetCommandBufferForUpdate()
|
||||
const D3D12CommandList& GSTexture12::GetCommandBufferForUpdate()
|
||||
{
|
||||
GSDevice12* const dev = GSDevice12::GetInstance();
|
||||
if (m_type != Type::Texture || m_use_fence_counter == dev->GetCurrentFenceValue())
|
||||
@@ -476,10 +551,20 @@ ID3D12Resource* GSTexture12::AllocateUploadStagingBuffer(
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||
|
||||
const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_UPLOAD};
|
||||
const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_size, 1, 1, 1,
|
||||
DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE};
|
||||
HRESULT hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource(&allocation_desc, &resource_desc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.put(), IID_PPV_ARGS(resource.put()));
|
||||
|
||||
const GSDevice12::D3D12_RESOURCE_DESCU resource_desc = {{D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_size, 1, 1, 1,
|
||||
DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}};
|
||||
HRESULT hr;
|
||||
if (GSDevice12::GetInstance()->UseEnhancedBarriers())
|
||||
{
|
||||
hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource3(&allocation_desc, &resource_desc.desc1,
|
||||
D3D12_BARRIER_LAYOUT_UNDEFINED, nullptr, 0, nullptr, allocation.put(), IID_PPV_ARGS(resource.put()));
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource(&allocation_desc, &resource_desc.desc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.put(), IID_PPV_ARGS(resource.put()));
|
||||
}
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.WriteLn("(AllocateUploadStagingBuffer) CreateCommittedResource() failed with %08X", hr);
|
||||
@@ -564,14 +649,14 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l
|
||||
sbuffer.CommitMemory(required_size);
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList* cmdlist = GetCommandBufferForUpdate();
|
||||
const D3D12CommandList& cmdlist = GetCommandBufferForUpdate();
|
||||
GL_PUSH("GSTexture12::Update({%d,%d} %dx%d Lvl:%u", r.x, r.y, r.width(), r.height(), layer);
|
||||
|
||||
// first time the texture is used? don't leave it undefined
|
||||
if (m_resource_state == D3D12_RESOURCE_STATE_COMMON)
|
||||
TransitionToState(cmdlist, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
else if (m_resource_state != D3D12_RESOURCE_STATE_COPY_DEST)
|
||||
TransitionSubresourceToState(cmdlist, layer, m_resource_state, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
if (m_resource_state == GSTexture12::ResourceState::Undefined)
|
||||
TransitionToState(cmdlist, GSTexture12::ResourceState::CopyDst);
|
||||
else if (m_resource_state != GSTexture12::ResourceState::CopyDst)
|
||||
TransitionSubresourceToState(cmdlist, layer, m_resource_state, GSTexture12::ResourceState::CopyDst);
|
||||
|
||||
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
|
||||
if (m_type == Type::RenderTarget)
|
||||
@@ -588,11 +673,11 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l
|
||||
dstloc.SubresourceIndex = layer;
|
||||
|
||||
const D3D12_BOX srcbox{0u, 0u, 0u, width, height, 1u};
|
||||
cmdlist->CopyTextureRegion(&dstloc, Common::AlignDownPow2((u32)r.x, block_size),
|
||||
cmdlist.list4->CopyTextureRegion(&dstloc, Common::AlignDownPow2((u32)r.x, block_size),
|
||||
Common::AlignDownPow2((u32)r.y, block_size), 0, &srcloc, &srcbox);
|
||||
|
||||
if (m_resource_state != D3D12_RESOURCE_STATE_COPY_DEST)
|
||||
TransitionSubresourceToState(cmdlist, layer, D3D12_RESOURCE_STATE_COPY_DEST, m_resource_state);
|
||||
if (m_resource_state != GSTexture12::ResourceState::CopyDst)
|
||||
TransitionSubresourceToState(cmdlist, layer, GSTexture12::ResourceState::CopyDst, m_resource_state);
|
||||
|
||||
if (m_type == Type::Texture)
|
||||
m_needs_mipmaps_generated |= (layer == 0);
|
||||
@@ -642,15 +727,15 @@ void GSTexture12::Unmap()
|
||||
const u32 buffer_offset = buffer.GetCurrentOffset();
|
||||
buffer.CommitMemory(required_size);
|
||||
|
||||
ID3D12GraphicsCommandList* cmdlist = GetCommandBufferForUpdate();
|
||||
const D3D12CommandList& cmdlist = GetCommandBufferForUpdate();
|
||||
GL_PUSH("GSTexture12::Update({%d,%d} %dx%d Lvl:%u", m_map_area.x, m_map_area.y, m_map_area.width(),
|
||||
m_map_area.height(), m_map_level);
|
||||
|
||||
// first time the texture is used? don't leave it undefined
|
||||
if (m_resource_state == D3D12_RESOURCE_STATE_COMMON)
|
||||
TransitionToState(cmdlist, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
else if (m_resource_state != D3D12_RESOURCE_STATE_COPY_DEST)
|
||||
TransitionSubresourceToState(cmdlist, m_map_level, m_resource_state, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
if (m_resource_state == ResourceState::Undefined)
|
||||
TransitionToState(cmdlist, ResourceState::CopyDst);
|
||||
else if (m_resource_state != ResourceState::CopyDst)
|
||||
TransitionSubresourceToState(cmdlist, m_map_level, m_resource_state, ResourceState::CopyDst);
|
||||
|
||||
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
|
||||
if (m_type == Type::RenderTarget)
|
||||
@@ -677,10 +762,10 @@ void GSTexture12::Unmap()
|
||||
dstloc.SubresourceIndex = m_map_level;
|
||||
|
||||
const D3D12_BOX srcbox{0u, 0u, 0u, width, height, 1};
|
||||
cmdlist->CopyTextureRegion(&dstloc, m_map_area.x, m_map_area.y, 0, &srcloc, &srcbox);
|
||||
cmdlist.list4->CopyTextureRegion(&dstloc, m_map_area.x, m_map_area.y, 0, &srcloc, &srcbox);
|
||||
|
||||
if (m_resource_state != D3D12_RESOURCE_STATE_COPY_DEST)
|
||||
TransitionSubresourceToState(cmdlist, m_map_level, D3D12_RESOURCE_STATE_COPY_DEST, m_resource_state);
|
||||
if (m_resource_state != ResourceState::CopyDst)
|
||||
TransitionSubresourceToState(cmdlist, m_map_level, ResourceState::CopyDst, m_resource_state);
|
||||
|
||||
if (m_type == Type::Texture)
|
||||
m_needs_mipmaps_generated |= (m_map_level == 0);
|
||||
@@ -717,55 +802,343 @@ void GSTexture12::SetDebugName(std::string_view name)
|
||||
|
||||
#endif
|
||||
|
||||
void GSTexture12::TransitionToState(D3D12_RESOURCE_STATES state)
|
||||
void GSTexture12::TransitionToState(ResourceState state)
|
||||
{
|
||||
TransitionToState(GSDevice12::GetInstance()->GetCommandList(), state);
|
||||
}
|
||||
|
||||
void GSTexture12::TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state)
|
||||
void GSTexture12::TransitionToState(const D3D12CommandList& cmdlist, ResourceState state)
|
||||
{
|
||||
if (m_resource_state == state)
|
||||
return;
|
||||
|
||||
// Read only depth requires special handling as we might want to write stencil.
|
||||
// Also batch the transition barriers as per recommendation from docs.
|
||||
if (state == (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE))
|
||||
{
|
||||
// Transition to read depth/write stencil
|
||||
const D3D12_RESOURCE_BARRIER barriers[2] = {
|
||||
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
{{m_resource.get(), 0, m_resource_state, (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)}}},
|
||||
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
{{m_resource.get(), 1, m_resource_state, D3D12_RESOURCE_STATE_DEPTH_WRITE}}},
|
||||
};
|
||||
cmdlist->ResourceBarrier(m_resource_state == D3D12_RESOURCE_STATE_DEPTH_WRITE ? 1 : 2, barriers);
|
||||
}
|
||||
else if (m_resource_state == (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE))
|
||||
{
|
||||
// Transition from read depth/write stencil
|
||||
const D3D12_RESOURCE_BARRIER barriers[2] = {
|
||||
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
{{m_resource.get(), 0, (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), state}}},
|
||||
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
{{m_resource.get(), 1, D3D12_RESOURCE_STATE_DEPTH_WRITE, state}}},
|
||||
};
|
||||
cmdlist->ResourceBarrier(state == D3D12_RESOURCE_STATE_DEPTH_WRITE ? 1 : 2, barriers);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal transition
|
||||
TransitionSubresourceToState(cmdlist, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, m_resource_state, state);
|
||||
}
|
||||
TransitionSubresourceToState(cmdlist, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, m_resource_state, state);
|
||||
|
||||
m_resource_state = state;
|
||||
}
|
||||
|
||||
void GSTexture12::TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, int level,
|
||||
D3D12_RESOURCE_STATES before_state, D3D12_RESOURCE_STATES after_state) const
|
||||
void GSTexture12::TransitionSubresourceToState(const D3D12CommandList& cmdlist, int level,
|
||||
ResourceState before_state, ResourceState after_state) const
|
||||
{
|
||||
const D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
{{m_resource.get(), static_cast<u32>(level), before_state, after_state}}};
|
||||
cmdlist->ResourceBarrier(1, &barrier);
|
||||
if (GSDevice12::GetInstance()->UseEnhancedBarriers())
|
||||
{
|
||||
// Read only depth requires special handling as we might want to write stencil.
|
||||
// We need to transition subresources separately, requiring 2 barriers
|
||||
// Handling it here allows us to batch those barriers.
|
||||
// Other transitions only need the one barrier.
|
||||
D3D12_TEXTURE_BARRIER barriers[2] = {{D3D12_BARRIER_SYNC_NONE, D3D12_BARRIER_SYNC_NONE,
|
||||
D3D12_BARRIER_ACCESS_COMMON, D3D12_BARRIER_ACCESS_COMMON,
|
||||
D3D12_BARRIER_LAYOUT_COMMON, D3D12_BARRIER_LAYOUT_COMMON,
|
||||
m_resource.get(), {static_cast<u32>(level), 0, 0, 0, 0, 0}, D3D12_TEXTURE_BARRIER_FLAG_NONE}};
|
||||
|
||||
uint num_barriers = 1;
|
||||
D3D12_TEXTURE_BARRIER& barrier = barriers[0];
|
||||
switch (before_state)
|
||||
{
|
||||
case ResourceState::Undefined:
|
||||
case ResourceState::Present:
|
||||
barrier.LayoutBefore = D3D12_BARRIER_LAYOUT_COMMON;
|
||||
barrier.AccessBefore = D3D12_BARRIER_ACCESS_NO_ACCESS;
|
||||
barrier.SyncBefore = D3D12_BARRIER_SYNC_NONE;
|
||||
break;
|
||||
case ResourceState::RenderTarget:
|
||||
barrier.LayoutBefore = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_RENDER_TARGET;
|
||||
barrier.AccessBefore = m_simultaneous_tex ?
|
||||
D3D12_BARRIER_ACCESS_RENDER_TARGET | D3D12_BARRIER_ACCESS_SHADER_RESOURCE :
|
||||
D3D12_BARRIER_ACCESS_RENDER_TARGET;
|
||||
barrier.SyncBefore = m_simultaneous_tex ?
|
||||
D3D12_BARRIER_SYNC_RENDER_TARGET | D3D12_BARRIER_SYNC_PIXEL_SHADING :
|
||||
D3D12_BARRIER_SYNC_RENDER_TARGET;
|
||||
break;
|
||||
case ResourceState::DepthWriteStencil:
|
||||
pxAssert(!m_simultaneous_tex);
|
||||
barrier.LayoutBefore = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE;
|
||||
barrier.AccessBefore = D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE;
|
||||
barrier.SyncBefore = D3D12_BARRIER_SYNC_DEPTH_STENCIL;
|
||||
break;
|
||||
case ResourceState::DepthReadStencil:
|
||||
pxAssert(!m_simultaneous_tex);
|
||||
pxAssert(level == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);
|
||||
|
||||
barriers[0].Subresources = {0, static_cast<uint>(m_mipmap_levels), 0, 1, 0, 1};
|
||||
barriers[0].LayoutBefore = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ;
|
||||
barriers[0].AccessBefore = D3D12_BARRIER_ACCESS_SHADER_RESOURCE | D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ;
|
||||
barriers[0].SyncBefore = D3D12_BARRIER_SYNC_DEPTH_STENCIL | D3D12_BARRIER_SYNC_PIXEL_SHADING;
|
||||
if (after_state != ResourceState::DepthWriteStencil)
|
||||
{
|
||||
num_barriers = 2;
|
||||
barriers[1].Subresources = {0, static_cast<uint>(m_mipmap_levels), 0, 1, 1, 1};
|
||||
barriers[1].LayoutBefore = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE;
|
||||
barriers[1].AccessBefore = D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ;
|
||||
barriers[1].SyncBefore = D3D12_BARRIER_SYNC_DEPTH_STENCIL;
|
||||
}
|
||||
break;
|
||||
case ResourceState::PixelShaderResource:
|
||||
barrier.LayoutBefore = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;
|
||||
barrier.AccessBefore = D3D12_BARRIER_ACCESS_SHADER_RESOURCE;
|
||||
barrier.SyncBefore = D3D12_BARRIER_SYNC_PIXEL_SHADING;
|
||||
break;
|
||||
case ResourceState::ComputeShaderResource:
|
||||
barrier.LayoutBefore = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;
|
||||
barrier.AccessBefore = D3D12_BARRIER_ACCESS_SHADER_RESOURCE;
|
||||
barrier.SyncBefore = D3D12_BARRIER_SYNC_COMPUTE_SHADING;
|
||||
break;
|
||||
case ResourceState::CopySrc:
|
||||
barrier.LayoutBefore = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE;
|
||||
barrier.AccessBefore = D3D12_BARRIER_ACCESS_COPY_SOURCE;
|
||||
barrier.SyncBefore = D3D12_BARRIER_SYNC_COPY;
|
||||
break;
|
||||
case ResourceState::CopyDst:
|
||||
barrier.LayoutBefore = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_DEST;
|
||||
barrier.AccessBefore = D3D12_BARRIER_ACCESS_COPY_DEST;
|
||||
barrier.SyncBefore = D3D12_BARRIER_SYNC_COPY;
|
||||
break;
|
||||
case ResourceState::CASShaderUAV:
|
||||
barrier.LayoutBefore = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;
|
||||
barrier.AccessBefore = D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;
|
||||
barrier.SyncBefore = D3D12_BARRIER_SYNC_COMPUTE_SHADING;
|
||||
break;
|
||||
case ResourceState::PixelShaderUAV:
|
||||
barrier.LayoutBefore = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;
|
||||
barrier.AccessBefore = D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;
|
||||
barrier.SyncBefore = D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_CLEAR_UNORDERED_ACCESS_VIEW;
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
barrier.LayoutBefore = D3D12_BARRIER_LAYOUT_UNDEFINED;
|
||||
barrier.AccessBefore = D3D12_BARRIER_ACCESS_NO_ACCESS;
|
||||
barrier.SyncBefore = D3D12_BARRIER_SYNC_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (after_state)
|
||||
{
|
||||
case ResourceState::Undefined:
|
||||
case ResourceState::Present:
|
||||
barrier.LayoutAfter = D3D12_BARRIER_LAYOUT_COMMON;
|
||||
barrier.AccessAfter = D3D12_BARRIER_ACCESS_NO_ACCESS;
|
||||
barrier.SyncAfter = D3D12_BARRIER_SYNC_NONE;
|
||||
break;
|
||||
case ResourceState::RenderTarget:
|
||||
barrier.LayoutAfter = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_RENDER_TARGET;
|
||||
barrier.AccessAfter = m_simultaneous_tex ?
|
||||
D3D12_BARRIER_ACCESS_RENDER_TARGET | D3D12_BARRIER_ACCESS_SHADER_RESOURCE :
|
||||
D3D12_BARRIER_ACCESS_RENDER_TARGET;
|
||||
barrier.SyncAfter = m_simultaneous_tex ?
|
||||
D3D12_BARRIER_SYNC_RENDER_TARGET | D3D12_BARRIER_SYNC_PIXEL_SHADING :
|
||||
D3D12_BARRIER_SYNC_RENDER_TARGET;
|
||||
break;
|
||||
case ResourceState::DepthWriteStencil:
|
||||
pxAssert(!m_simultaneous_tex);
|
||||
barrier.LayoutAfter = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE;
|
||||
barrier.AccessAfter = D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE;
|
||||
barrier.SyncAfter = D3D12_BARRIER_SYNC_DEPTH_STENCIL;
|
||||
break;
|
||||
case ResourceState::DepthReadStencil:
|
||||
pxAssert(!m_simultaneous_tex);
|
||||
pxAssert(level == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);
|
||||
|
||||
barriers[0].Subresources = {0, static_cast<uint>(m_mipmap_levels), 0, 1, 0, 1};
|
||||
barriers[0].LayoutAfter = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ;
|
||||
barriers[0].AccessAfter = D3D12_BARRIER_ACCESS_SHADER_RESOURCE | D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ;
|
||||
barriers[0].SyncAfter = D3D12_BARRIER_SYNC_DEPTH_STENCIL | D3D12_BARRIER_SYNC_PIXEL_SHADING;
|
||||
if (before_state != ResourceState::DepthWriteStencil)
|
||||
{
|
||||
num_barriers = 2;
|
||||
barriers[1].Subresources = {0, static_cast<uint>(m_mipmap_levels), 0, 1, 1, 1};
|
||||
barriers[1].LayoutAfter = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE;
|
||||
barriers[1].AccessAfter = D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ;
|
||||
barriers[1].SyncAfter = D3D12_BARRIER_SYNC_DEPTH_STENCIL;
|
||||
}
|
||||
break;
|
||||
case ResourceState::PixelShaderResource:
|
||||
barrier.LayoutAfter = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;
|
||||
barrier.AccessAfter = D3D12_BARRIER_ACCESS_SHADER_RESOURCE;
|
||||
barrier.SyncAfter = D3D12_BARRIER_SYNC_PIXEL_SHADING;
|
||||
break;
|
||||
case ResourceState::ComputeShaderResource:
|
||||
barrier.LayoutAfter = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;
|
||||
barrier.AccessAfter = D3D12_BARRIER_ACCESS_SHADER_RESOURCE;
|
||||
barrier.SyncAfter = D3D12_BARRIER_SYNC_COMPUTE_SHADING;
|
||||
break;
|
||||
case ResourceState::CopySrc:
|
||||
barrier.LayoutAfter = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE;
|
||||
barrier.AccessAfter = D3D12_BARRIER_ACCESS_COPY_SOURCE;
|
||||
barrier.SyncAfter = D3D12_BARRIER_SYNC_COPY;
|
||||
break;
|
||||
case ResourceState::CopyDst:
|
||||
barrier.LayoutAfter = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_DEST;
|
||||
barrier.AccessAfter = D3D12_BARRIER_ACCESS_COPY_DEST;
|
||||
barrier.SyncAfter = D3D12_BARRIER_SYNC_COPY;
|
||||
break;
|
||||
case ResourceState::CASShaderUAV:
|
||||
barrier.LayoutAfter = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;
|
||||
barrier.AccessAfter = D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;
|
||||
barrier.SyncAfter = D3D12_BARRIER_SYNC_COMPUTE_SHADING;
|
||||
break;
|
||||
case ResourceState::PixelShaderUAV:
|
||||
barrier.LayoutAfter = m_simultaneous_tex ? D3D12_BARRIER_LAYOUT_COMMON : D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;
|
||||
barrier.AccessAfter = D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;
|
||||
barrier.SyncAfter = D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_CLEAR_UNORDERED_ACCESS_VIEW;
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
barrier.LayoutAfter = D3D12_BARRIER_LAYOUT_UNDEFINED;
|
||||
barrier.AccessAfter = D3D12_BARRIER_ACCESS_NO_ACCESS;
|
||||
barrier.SyncAfter = D3D12_BARRIER_SYNC_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (num_barriers == 2)
|
||||
{
|
||||
barriers[1].pResource = m_resource.get();
|
||||
barriers[1].Flags = barriers[0].Flags;
|
||||
if (before_state == ResourceState::DepthReadStencil)
|
||||
{
|
||||
barriers[1].LayoutAfter = barriers[0].LayoutAfter;
|
||||
barriers[1].AccessAfter = barriers[0].AccessAfter;
|
||||
barriers[1].SyncAfter = barriers[0].SyncAfter;
|
||||
}
|
||||
else // after_state == ResourceState::DepthReadStencil
|
||||
{
|
||||
barriers[1].LayoutBefore = barriers[0].LayoutBefore;
|
||||
barriers[1].AccessBefore = barriers[0].AccessBefore;
|
||||
barriers[1].SyncBefore = barriers[0].SyncBefore;
|
||||
}
|
||||
}
|
||||
|
||||
const D3D12_BARRIER_GROUP group = {.Type = D3D12_BARRIER_TYPE_TEXTURE, .NumBarriers = num_barriers, .pTextureBarriers = barriers};
|
||||
cmdlist.list7->Barrier(1, &group);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read only depth requires special handling as we might want to write stencil.
|
||||
// We need to transition subresources separately, requiring 2 barriers.
|
||||
// Handling it here allows us to batch those barriers.
|
||||
// Other transitions only need the one barrier.
|
||||
D3D12_RESOURCE_BARRIER barriers[2] = {{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
{{m_resource.get(), static_cast<u32>(level), D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COMMON}}}};
|
||||
|
||||
int num_barriers = 1;
|
||||
D3D12_RESOURCE_BARRIER& barrier = barriers[0];
|
||||
switch (before_state)
|
||||
{
|
||||
case ResourceState::Undefined:
|
||||
case ResourceState::Present:
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
|
||||
break;
|
||||
case ResourceState::RenderTarget:
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
break;
|
||||
case ResourceState::DepthWriteStencil:
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
||||
break;
|
||||
case ResourceState::DepthReadStencil:
|
||||
pxAssert(!m_simultaneous_tex);
|
||||
pxAssert(m_mipmap_levels == 1);
|
||||
pxAssert(level == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);
|
||||
|
||||
barriers[0].Transition.Subresource = 0;
|
||||
barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_DEPTH_READ;
|
||||
if (after_state != ResourceState::DepthWriteStencil)
|
||||
{
|
||||
num_barriers = 2;
|
||||
barriers[1].Transition.Subresource = 1;
|
||||
barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
||||
}
|
||||
break;
|
||||
case ResourceState::PixelShaderResource:
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
break;
|
||||
case ResourceState::ComputeShaderResource:
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
break;
|
||||
case ResourceState::CopySrc:
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
break;
|
||||
case ResourceState::CopyDst:
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
break;
|
||||
case ResourceState::CASShaderUAV:
|
||||
case ResourceState::PixelShaderUAV:
|
||||
// Handled in after_state cases.
|
||||
if (after_state == ResourceState::CASShaderUAV || after_state == ResourceState::PixelShaderUAV)
|
||||
break;
|
||||
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (after_state)
|
||||
{
|
||||
case ResourceState::Undefined:
|
||||
case ResourceState::Present:
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
|
||||
break;
|
||||
case ResourceState::RenderTarget:
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
break;
|
||||
case ResourceState::DepthWriteStencil:
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
||||
break;
|
||||
case ResourceState::DepthReadStencil:
|
||||
pxAssert(!m_simultaneous_tex);
|
||||
pxAssert(m_mipmap_levels == 1);
|
||||
pxAssert(level == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);
|
||||
|
||||
barriers[0].Transition.Subresource = 0;
|
||||
barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_DEPTH_READ;
|
||||
if (before_state != ResourceState::DepthWriteStencil)
|
||||
{
|
||||
num_barriers = 2;
|
||||
barriers[1].Transition.Subresource = 1;
|
||||
barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
||||
}
|
||||
break;
|
||||
case ResourceState::PixelShaderResource:
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
break;
|
||||
case ResourceState::ComputeShaderResource:
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
break;
|
||||
case ResourceState::CopySrc:
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
break;
|
||||
case ResourceState::CopyDst:
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
break;
|
||||
case ResourceState::CASShaderUAV:
|
||||
case ResourceState::PixelShaderUAV:
|
||||
if (before_state == ResourceState::CASShaderUAV || before_state == ResourceState::PixelShaderUAV)
|
||||
{
|
||||
// No state transition, but probably want a barrier instead.
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
|
||||
// pResource is a common initial member, so no need to set again.
|
||||
}
|
||||
else
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (num_barriers == 2)
|
||||
{
|
||||
barriers[1].Transition.pResource = m_resource.get();
|
||||
barriers[1].Type = barriers[0].Type;
|
||||
barriers[1].Flags = barriers[0].Flags;
|
||||
if (before_state == ResourceState::DepthReadStencil)
|
||||
barriers[1].Transition.StateAfter = barriers[0].Transition.StateAfter;
|
||||
else // after_state == ResourceState::DepthReadStencil
|
||||
barriers[1].Transition.StateBefore = barriers[0].Transition.StateBefore;
|
||||
}
|
||||
|
||||
cmdlist.list4->ResourceBarrier(num_barriers, barriers);
|
||||
}
|
||||
}
|
||||
|
||||
void GSTexture12::CommitClear()
|
||||
@@ -774,22 +1147,21 @@ void GSTexture12::CommitClear()
|
||||
return;
|
||||
|
||||
GSDevice12::GetInstance()->EndRenderPass();
|
||||
|
||||
CommitClear(GSDevice12::GetInstance()->GetCommandList());
|
||||
}
|
||||
|
||||
void GSTexture12::CommitClear(ID3D12GraphicsCommandList* cmdlist)
|
||||
void GSTexture12::CommitClear(const D3D12CommandList& cmdlist)
|
||||
{
|
||||
if (IsDepthStencil())
|
||||
{
|
||||
TransitionToState(cmdlist, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
cmdlist->ClearDepthStencilView(
|
||||
TransitionToState(cmdlist, ResourceState::DepthWriteStencil);
|
||||
cmdlist.list4->ClearDepthStencilView(
|
||||
GetWriteDescriptor(), D3D12_CLEAR_FLAG_DEPTH, m_clear_value.depth, 0, 0, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
cmdlist->ClearRenderTargetView(GetWriteDescriptor(), GSVector4::unorm8(m_clear_value.color).v, 0, nullptr);
|
||||
TransitionToState(cmdlist, ResourceState::RenderTarget);
|
||||
cmdlist.list4->ClearRenderTargetView(GetWriteDescriptor(), GSVector4::unorm8(m_clear_value.color).v, 0, nullptr);
|
||||
}
|
||||
|
||||
SetState(GSTexture::State::Dirty);
|
||||
@@ -816,14 +1188,23 @@ std::unique_ptr<GSDownloadTexture12> GSDownloadTexture12::Create(u32 width, u32
|
||||
D3D12MA::ALLOCATION_DESC allocation_desc = {};
|
||||
allocation_desc.HeapType = D3D12_HEAP_TYPE_READBACK;
|
||||
|
||||
const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_size, 1, 1, 1,
|
||||
DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE};
|
||||
const GSDevice12::D3D12_RESOURCE_DESCU resource_desc = {{D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_size, 1, 1, 1,
|
||||
DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}};
|
||||
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||
wil::com_ptr_nothrow<ID3D12Resource> buffer;
|
||||
|
||||
HRESULT hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource(&allocation_desc, &resource_desc,
|
||||
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
|
||||
HRESULT hr;
|
||||
if (GSDevice12::GetInstance()->UseEnhancedBarriers())
|
||||
{
|
||||
hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource3(&allocation_desc, &resource_desc.desc1,
|
||||
D3D12_BARRIER_LAYOUT_UNDEFINED, nullptr, 0, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource(&allocation_desc, &resource_desc.desc,
|
||||
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
|
||||
}
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("(GSDownloadTexture12::Create) CreateResource() failed with HRESULT %08X", hr);
|
||||
@@ -861,7 +1242,7 @@ void GSDownloadTexture12::CopyFromTexture(
|
||||
if (IsMapped())
|
||||
Unmap();
|
||||
|
||||
ID3D12GraphicsCommandList* cmdlist = GSDevice12::GetInstance()->GetCommandList();
|
||||
const D3D12CommandList& cmdlist = GSDevice12::GetInstance()->GetCommandList();
|
||||
GL_INS("ReadbackTexture: {%d,%d} %ux%u", src.left, src.top, src.width(), src.height());
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION srcloc;
|
||||
@@ -879,17 +1260,17 @@ void GSDownloadTexture12::CopyFromTexture(
|
||||
dstloc.PlacedFootprint.Footprint.Depth = 1;
|
||||
dstloc.PlacedFootprint.Footprint.RowPitch = m_current_pitch;
|
||||
|
||||
const D3D12_RESOURCE_STATES old_layout = tex12->GetResourceState();
|
||||
if (old_layout != D3D12_RESOURCE_STATE_COPY_SOURCE)
|
||||
tex12->TransitionSubresourceToState(cmdlist, src_level, old_layout, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
const GSTexture12::ResourceState old_layout = tex12->GetResourceState();
|
||||
if (old_layout != GSTexture12::ResourceState::CopySrc)
|
||||
tex12->TransitionSubresourceToState(cmdlist, src_level, old_layout, GSTexture12::ResourceState::CopySrc);
|
||||
|
||||
// TODO: Rules for depth buffers here?
|
||||
const D3D12_BOX srcbox{static_cast<UINT>(src.left), static_cast<UINT>(src.top), 0u, static_cast<UINT>(src.right),
|
||||
static_cast<UINT>(src.bottom), 1u};
|
||||
cmdlist->CopyTextureRegion(&dstloc, 0, 0, 0, &srcloc, &srcbox);
|
||||
cmdlist.list4->CopyTextureRegion(&dstloc, 0, 0, 0, &srcloc, &srcbox);
|
||||
|
||||
if (old_layout != D3D12_RESOURCE_STATE_COPY_SOURCE)
|
||||
tex12->TransitionSubresourceToState(cmdlist, src_level, D3D12_RESOURCE_STATE_COPY_SOURCE, old_layout);
|
||||
if (old_layout != GSTexture12::ResourceState::CopySrc)
|
||||
tex12->TransitionSubresourceToState(cmdlist, src_level, GSTexture12::ResourceState::CopySrc, old_layout);
|
||||
|
||||
m_copy_fence_value = GSDevice12::GetInstance()->GetCurrentFenceValue();
|
||||
m_needs_flush = true;
|
||||
|
||||
@@ -16,9 +16,27 @@ namespace D3D12MA
|
||||
class Allocation;
|
||||
}
|
||||
|
||||
struct D3D12CommandList;
|
||||
|
||||
class GSTexture12 final : public GSTexture
|
||||
{
|
||||
public:
|
||||
enum class ResourceState : u32
|
||||
{
|
||||
Undefined,
|
||||
Present,
|
||||
RenderTarget,
|
||||
DepthWriteStencil,
|
||||
DepthReadStencil,
|
||||
PixelShaderResource,
|
||||
ComputeShaderResource,
|
||||
CopySrc,
|
||||
CopyDst,
|
||||
CASShaderUAV, // No Clear UAV Sync
|
||||
PixelShaderUAV,
|
||||
Count
|
||||
};
|
||||
|
||||
~GSTexture12() override;
|
||||
|
||||
static std::unique_ptr<GSTexture12> Create(Type type, Format format, int width, int height, int levels,
|
||||
@@ -26,14 +44,14 @@ public:
|
||||
DXGI_FORMAT uav_format);
|
||||
static std::unique_ptr<GSTexture12> Adopt(wil::com_ptr_nothrow<ID3D12Resource> resource, Type type, Format format,
|
||||
int width, int height, int levels, DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format,
|
||||
DXGI_FORMAT dsv_format, DXGI_FORMAT uav_format, D3D12_RESOURCE_STATES resource_state);
|
||||
DXGI_FORMAT dsv_format, DXGI_FORMAT uav_format, ResourceState resource_state);
|
||||
|
||||
__fi const D3D12DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; }
|
||||
__fi const D3D12DescriptorHandle& GetWriteDescriptor() const { return m_write_descriptor; }
|
||||
__fi const D3D12DescriptorHandle& GetReadDepthViewDescriptor() const { return m_read_dsv_descriptor; }
|
||||
__fi const D3D12DescriptorHandle& GetUAVDescriptor() const { return m_uav_descriptor; }
|
||||
__fi const D3D12DescriptorHandle& GetFBLDescriptor() const { return m_fbl_descriptor; }
|
||||
__fi D3D12_RESOURCE_STATES GetResourceState() const { return m_resource_state; }
|
||||
__fi ResourceState GetResourceState() const { return m_resource_state; }
|
||||
__fi DXGI_FORMAT GetDXGIFormat() const { return m_dxgi_format; }
|
||||
__fi ID3D12Resource* GetResource() const { return m_resource.get(); }
|
||||
__fi ID3D12Resource* GetFBLResource() const { return m_resource_fbl.get(); }
|
||||
@@ -49,15 +67,15 @@ public:
|
||||
void SetDebugName(std::string_view name) override;
|
||||
#endif
|
||||
|
||||
void TransitionToState(D3D12_RESOURCE_STATES state);
|
||||
void TransitionToState(ResourceState state);
|
||||
void CommitClear();
|
||||
void CommitClear(ID3D12GraphicsCommandList* cmdlist);
|
||||
void CommitClear(const D3D12CommandList& cmdlist);
|
||||
|
||||
void Destroy(bool defer = true);
|
||||
|
||||
void TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state);
|
||||
void TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, int level, D3D12_RESOURCE_STATES before_state,
|
||||
D3D12_RESOURCE_STATES after_state) const;
|
||||
void TransitionToState(const D3D12CommandList&, ResourceState state);
|
||||
void TransitionSubresourceToState(const D3D12CommandList& cmdlist, int level, ResourceState before_state,
|
||||
ResourceState after_state) const;
|
||||
|
||||
// Call when the texture is bound to the pipeline, or read from in a copy.
|
||||
__fi void SetUseFenceCounter(u64 val) { m_use_fence_counter = val; }
|
||||
@@ -75,7 +93,7 @@ private:
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
|
||||
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& ro_dsv_descriptor,
|
||||
const D3D12DescriptorHandle& uav_descriptor, const D3D12DescriptorHandle& fbl_descriptor,
|
||||
WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state);
|
||||
WriteDescriptorType wdtype, bool simultaneous_texture, ResourceState resource_state);
|
||||
|
||||
static bool CreateSRVDescriptor(
|
||||
ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
|
||||
@@ -83,7 +101,7 @@ private:
|
||||
static bool CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh, bool read_only);
|
||||
static bool CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
|
||||
|
||||
ID3D12GraphicsCommandList* GetCommandBufferForUpdate();
|
||||
const D3D12CommandList& GetCommandBufferForUpdate();
|
||||
ID3D12Resource* AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 height) const;
|
||||
void CopyTextureDataForUpload(void* dst, const void* src, u32 pitch, u32 upload_pitch, u32 height) const;
|
||||
|
||||
@@ -99,7 +117,11 @@ private:
|
||||
WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None;
|
||||
|
||||
DXGI_FORMAT m_dxgi_format = DXGI_FORMAT_UNKNOWN;
|
||||
D3D12_RESOURCE_STATES m_resource_state = D3D12_RESOURCE_STATE_COMMON;
|
||||
ResourceState m_resource_state = ResourceState::Undefined;
|
||||
|
||||
// With legacy barriers, an aliased resource is used as the feedback shader resource.
|
||||
// With enhanced barriers, the layout is always COMMON, but can use the main resource for feedback.
|
||||
bool m_simultaneous_tex;
|
||||
|
||||
// Contains the fence counter when the texture was last used.
|
||||
// When this matches the current fence counter, the texture was used this command buffer.
|
||||
|
||||
@@ -39,21 +39,83 @@ static bool s_nativeres;
|
||||
|
||||
bool GSHwHack::GSC_IRem(GSRendererHW& r, int& skip)
|
||||
{
|
||||
static bool first_shuffle = false;
|
||||
|
||||
if (skip > 0)
|
||||
{
|
||||
if (skip == 1 && first_shuffle)
|
||||
{
|
||||
first_shuffle = false;
|
||||
|
||||
GIFRegTEX0 RTLookup = GIFRegTEX0::Create(RTBP0, RFBW, RFPSM);
|
||||
GSTextureCache::Source* src = g_texture_cache->LookupSource(true, RTLookup, r.m_cached_ctx.TEXA, r.m_cached_ctx.CLAMP, GSVector4i(0, 0, 1, 1), nullptr, true, false, r.m_cached_ctx.FRAME, true, true);
|
||||
|
||||
GSTextureCache::Target* rt = g_texture_cache->LookupTarget(GIFRegTEX0::Create(RTBP0, RFBW, RFPSM),
|
||||
GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget, true, 0, false, false, true, true, GSVector4i(0, 0, 1, 1), true, false, true, src);
|
||||
|
||||
if (!rt)
|
||||
return false;
|
||||
|
||||
GSLocalMemory::psm_t rt_psm = GSLocalMemory::m_psm[RFPSM];
|
||||
int page_offset = (RTBP0 - rt->m_TEX0.TBP0) >> 5;
|
||||
int vertical_offset = page_offset / std::max(rt->m_TEX0.TBW, 1U) * rt_psm.pgs.y;
|
||||
int horizontal_offset = page_offset % std::max(rt->m_TEX0.TBW, 1U) * rt_psm.pgs.x;
|
||||
|
||||
GSVector4i draw_size = GSVector4i(0, 0, 64, 32) + GSVector4i(horizontal_offset, vertical_offset, horizontal_offset, vertical_offset);
|
||||
rt->UnscaleRTAlpha();
|
||||
|
||||
// We need the original red back now for the next channel shuffle.
|
||||
GSHWDrawConfig& config = r.BeginHLEHardwareDraw(
|
||||
rt->GetTexture(), nullptr, rt->GetScale(), rt->GetTexture(), rt->GetScale(), draw_size);
|
||||
config.ps.shuffle = 1;
|
||||
config.ps.dst_fmt = GSLocalMemory::PSM_FMT_32;
|
||||
config.ps.write_rg = 0;
|
||||
config.ps.shuffle_same = 0;
|
||||
config.ps.real16src = 0;
|
||||
config.ps.shuffle_across = 1;
|
||||
config.ps.process_rg = r.SHUFFLE_READWRITE;
|
||||
config.ps.process_ba = r.SHUFFLE_READWRITE;
|
||||
config.colormask.wrgba = 0;
|
||||
config.colormask.wr = 1;
|
||||
config.colormask.wb = 1;
|
||||
config.ps.rta_correction = 0;
|
||||
config.ps.rta_source_correction = 0;
|
||||
config.ps.tfx = TFX_DECAL;
|
||||
config.ps.tcc = true;
|
||||
r.EndHLEHardwareDraw(true);
|
||||
|
||||
rt->m_alpha_min = 0;
|
||||
rt->m_alpha_max = 255;
|
||||
|
||||
rt = nullptr;
|
||||
src = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
skip--;
|
||||
return !first_shuffle;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip == 0)
|
||||
{
|
||||
const int get_next_ctx = r.m_env.PRIM.CTXT;
|
||||
const GSDrawingContext& next_ctx = r.m_env.CTXT[get_next_ctx];
|
||||
|
||||
// Uses these to do some shuffle tricks, it breaks things for us
|
||||
r.m_env.SCANMSK.MSK = 0;
|
||||
r.m_prev_env.SCANMSK.MSK = 0;
|
||||
|
||||
// Game does alternate line channel shuffles with blending, we can't handle this and the first one does it, so skip the second.
|
||||
if (RTME && RTPSM == PSMT8 && (RTBP0 + 0x20) == next_ctx.TEX0.TBP0 && RFBP == next_ctx.FRAME.Block())
|
||||
{
|
||||
skip = 1;
|
||||
skip = 2;
|
||||
return false;
|
||||
}
|
||||
// Detect the deswizzling shuffle from depth, copying the RG and BA separately on each half of the page (ignore the split).
|
||||
if (RTME && RFBP != RTBP0 && RFPSM == PSMCT16S && RTPSM == PSMCT16S)
|
||||
{
|
||||
if (r.m_vt.m_max.p.x == 64 && r.m_vt.m_max.p.y == 64 && r.m_index.tail == 128)
|
||||
if (r.m_vt.m_max.p.x == 64 && r.m_vt.m_max.p.y == 64 && r.m_index->tail == 128)
|
||||
{
|
||||
const GSVector4i draw_size(r.m_vt.m_min.p.x, r.m_vt.m_min.p.y/2, r.m_vt.m_max.p.x, r.m_vt.m_max.p.y/2);
|
||||
const GSVector4i read_size(r.m_vt.m_min.t.x, r.m_vt.m_min.t.y/2, r.m_vt.m_max.t.x, r.m_vt.m_max.t.y/2);
|
||||
@@ -64,7 +126,7 @@ bool GSHwHack::GSC_IRem(GSRendererHW& r, int& skip)
|
||||
}
|
||||
|
||||
// Following the previous draw, it tries to copy everything read from depth and offset it by 2, for the alternate line channel shuffle (skipped above).
|
||||
if (RTBP0 == (RFBP - 0x20) && r.m_vt.m_max.p.x == 64 && r.m_vt.m_max.p.y == 34 && r.m_index.tail == 2)
|
||||
if (RTBP0 == (RFBP - 0x20) && r.m_vt.m_max.p.x == 64 && r.m_vt.m_max.p.y == 34 && r.m_index->tail == 2)
|
||||
{
|
||||
GSVector4i draw_size(r.m_vt.m_min.p.x, r.m_vt.m_min.p.y - 2.0f, r.m_vt.m_max.p.x, r.m_vt.m_max.p.y - 2.0f);
|
||||
GSVector4i read_size(r.m_vt.m_min.t.x, r.m_vt.m_min.t.y, r.m_vt.m_max.t.x, r.m_vt.m_max.t.y);
|
||||
@@ -90,7 +152,7 @@ bool GSHwHack::GSC_IRem(GSRendererHW& r, int& skip)
|
||||
draw_size = draw_size + GSVector4i(horizontal_offset, vertical_offset, horizontal_offset, vertical_offset);
|
||||
rt->UnscaleRTAlpha();
|
||||
|
||||
// Shuffle the blue channel in to red, leave green as-is.
|
||||
// Shuffle the blue channel in to red, but swap them, we'll need the original red later.
|
||||
GSHWDrawConfig& config = r.BeginHLEHardwareDraw(
|
||||
rt->GetTexture(), nullptr, rt->GetScale(), rt->GetTexture(), rt->GetScale(), draw_size);
|
||||
config.ps.shuffle = 1;
|
||||
@@ -99,10 +161,11 @@ bool GSHwHack::GSC_IRem(GSRendererHW& r, int& skip)
|
||||
config.ps.shuffle_same = 0;
|
||||
config.ps.real16src = 0;
|
||||
config.ps.shuffle_across = 1;
|
||||
config.ps.process_rg = r.SHUFFLE_WRITE;
|
||||
config.ps.process_ba = r.SHUFFLE_READ;
|
||||
config.ps.process_rg = r.SHUFFLE_READWRITE;
|
||||
config.ps.process_ba = r.SHUFFLE_READWRITE;
|
||||
config.colormask.wrgba = 0;
|
||||
config.colormask.wr = 1;
|
||||
config.colormask.wb = 1;
|
||||
config.ps.rta_correction = 0;
|
||||
config.ps.rta_source_correction = 0;
|
||||
config.ps.tfx = TFX_DECAL;
|
||||
@@ -114,6 +177,7 @@ bool GSHwHack::GSC_IRem(GSRendererHW& r, int& skip)
|
||||
|
||||
rt = nullptr;
|
||||
src = nullptr;
|
||||
first_shuffle = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,10 +264,10 @@ bool GSHwHack::GSC_SFEX3(GSRendererHW& r, int& skip)
|
||||
// Skipping is no good as the copy is used again later, and it causes a weird shimmer/echo effect every other frame.
|
||||
|
||||
// Add on the height from the second part of the draw to the first, to make it one big rect.
|
||||
r.m_vertex.buff[1].XYZ.Y += r.m_vertex.buff[r.m_vertex.tail - 1].XYZ.Y - r.m_context->XYOFFSET.OFY;
|
||||
r.m_vertex.buff[1].V = r.m_vertex.buff[r.m_vertex.tail - 1].V;
|
||||
r.m_vertex.tail = 2;
|
||||
r.m_index.tail = 2;
|
||||
r.m_vertex->buff[1].XYZ.Y += r.m_vertex->buff[r.m_vertex->tail - 1].XYZ.Y - r.m_context->XYOFFSET.OFY;
|
||||
r.m_vertex->buff[1].V = r.m_vertex->buff[r.m_vertex->tail - 1].V;
|
||||
r.m_vertex->tail = 2;
|
||||
r.m_index->tail = 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,9 +332,9 @@ bool GSHwHack::GSC_NamcoGames(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
if (!s_nativeres && r.PRIM->PRIM == GS_SPRITE && RTME && RTEX0.TFX == 1 && RFPSM == RTPSM && RTPSM == PSMCT32 && RFBMSK == 0xFF000000 && r.m_index.tail > 2)
|
||||
if (!s_nativeres && r.PRIM->PRIM == GS_SPRITE && RTME && RTEX0.TFX == 1 && RFPSM == RTPSM && RTPSM == PSMCT32 && RFBMSK == 0xFF000000 && r.m_index->tail > 2)
|
||||
{
|
||||
GSVertex* v = &r.m_vertex.buff[0];
|
||||
GSVertex* v = &r.m_vertex->buff[0];
|
||||
// Don't enable hack on native res.
|
||||
// Fixes ghosting/blur effect and white lines appearing in stages: Moonfit Wilderness, Acid Rain - caused by upscaling.
|
||||
// Game copies the framebuffer as individual page rects with slight offsets (like 1/16 of a pixel etc) which doesn't wokr well with upscaling.
|
||||
@@ -284,7 +348,7 @@ bool GSHwHack::GSC_NamcoGames(GSRendererHW& r, int& skip)
|
||||
else
|
||||
{
|
||||
// Fixes the alignment of the two halves for the heat haze on the temple stage.
|
||||
for (u32 i = 0; i < r.m_index.tail; i+=2)
|
||||
for (u32 i = 0; i < r.m_index->tail; i+=2)
|
||||
{
|
||||
v[i].XYZ.Y -= 0x8;
|
||||
}
|
||||
@@ -612,7 +676,7 @@ bool GSHwHack::GSC_NFSUndercover(GSRendererHW& r, int& skip)
|
||||
|
||||
if (RPRIM->TME && Frame.PSM == PSMCT16S && Frame.FBMSK != 0 && Frame.FBW == 10 && Texture.TBW == 1 && Texture.TBP0 == 0x02800 && Texture.PSM == PSMZ16S)
|
||||
{
|
||||
GSVertex* v = &r.m_vertex.buff[1];
|
||||
GSVertex* v = &r.m_vertex->buff[1];
|
||||
v[0].XYZ.X = static_cast<u16>(RCONTEXT->XYOFFSET.OFX + ((r.m_r.z * 2) << 4));
|
||||
v[0].XYZ.Y = static_cast<u16>(RCONTEXT->XYOFFSET.OFY + (r.m_r.w << 4));
|
||||
v[0].U = r.m_r.z << 4;
|
||||
@@ -623,8 +687,8 @@ bool GSHwHack::GSC_NFSUndercover(GSRendererHW& r, int& skip)
|
||||
r.m_vt.m_max.p.y = r.m_r.w;
|
||||
r.m_vt.m_max.t.x = r.m_r.z;
|
||||
r.m_vt.m_max.t.y = r.m_r.w;
|
||||
r.m_vertex.head = r.m_vertex.tail = r.m_vertex.next = 2;
|
||||
r.m_index.tail = 2;
|
||||
r.m_vertex->head = r.m_vertex->tail = r.m_vertex->next = 2;
|
||||
r.m_index->tail = 2;
|
||||
skip = 79;
|
||||
}
|
||||
else
|
||||
@@ -776,7 +840,7 @@ bool GSHwHack::GSC_Battlefield2(GSRendererHW& r, int& skip)
|
||||
|
||||
if (dst)
|
||||
{
|
||||
float dc = r.m_vertex.buff[1].XYZ.Z;
|
||||
float dc = r.m_vertex->buff[1].XYZ.Z;
|
||||
g_gs_device->ClearDepth(dst->m_texture, dc * std::exp2(-32.0f));
|
||||
}
|
||||
}
|
||||
@@ -794,9 +858,9 @@ bool GSHwHack::GSC_BlueTongueGames(GSRendererHW& r, int& skip)
|
||||
if (RPRIM->TME && RTEX0.TW == 3 && RTEX0.TH == 3 && RTEX0.PSM == 0 && RFRAME.FBMSK == 0x00FFFFFF && RFRAME.FBW == 8 && r.PCRTCDisplays.GetResolution().x > 512)
|
||||
{
|
||||
// Check we are drawing stripes
|
||||
for (u32 i = 1; i < r.m_vertex.tail; i+=2)
|
||||
for (u32 i = 1; i < r.m_vertex->tail; i+=2)
|
||||
{
|
||||
int value = (((r.m_vertex.buff[i].XYZ.X - r.m_vertex.buff[i - 1].XYZ.X) + 8) >> 4);
|
||||
int value = (((r.m_vertex->buff[i].XYZ.X - r.m_vertex->buff[i - 1].XYZ.X) + 8) >> 4);
|
||||
if (value != 32)
|
||||
return false;
|
||||
}
|
||||
@@ -808,18 +872,18 @@ bool GSHwHack::GSC_BlueTongueGames(GSRendererHW& r, int& skip)
|
||||
|
||||
for (int vert = 32; vert < 40; vert+=2)
|
||||
{
|
||||
r.m_vertex.buff[vert].XYZ.X = context->XYOFFSET.OFX + (((vert * 16) << 4) - 8);
|
||||
r.m_vertex.buff[vert].XYZ.Y = context->XYOFFSET.OFY;
|
||||
r.m_vertex.buff[vert].U = (vert * 16) << 4;
|
||||
r.m_vertex.buff[vert].V = 0;
|
||||
r.m_vertex.buff[vert+1].XYZ.X = context->XYOFFSET.OFX + ((((vert * 16) + 32) << 4) - 8);
|
||||
r.m_vertex.buff[vert+1].XYZ.Y = context->XYOFFSET.OFY + (r.PCRTCDisplays.GetResolution().y << 4) + 8;
|
||||
r.m_vertex.buff[vert+1].U = ((vert * 16) + 32) << 4;
|
||||
r.m_vertex.buff[vert+1].V = r.PCRTCDisplays.GetResolution().y << 4;
|
||||
r.m_vertex->buff[vert].XYZ.X = context->XYOFFSET.OFX + (((vert * 16) << 4) - 8);
|
||||
r.m_vertex->buff[vert].XYZ.Y = context->XYOFFSET.OFY;
|
||||
r.m_vertex->buff[vert].U = (vert * 16) << 4;
|
||||
r.m_vertex->buff[vert].V = 0;
|
||||
r.m_vertex->buff[vert+1].XYZ.X = context->XYOFFSET.OFX + ((((vert * 16) + 32) << 4) - 8);
|
||||
r.m_vertex->buff[vert+1].XYZ.Y = context->XYOFFSET.OFY + (r.PCRTCDisplays.GetResolution().y << 4) + 8;
|
||||
r.m_vertex->buff[vert+1].U = ((vert * 16) + 32) << 4;
|
||||
r.m_vertex->buff[vert+1].V = r.PCRTCDisplays.GetResolution().y << 4;
|
||||
}
|
||||
|
||||
/*r.m_vertex.head = r.m_vertex.tail = r.m_vertex.next = 2;
|
||||
r.m_index.tail = 2;*/
|
||||
/*r.m_vertex->head = r.m_vertex->tail = r.m_vertex->next = 2;
|
||||
r.m_index->tail = 2;*/
|
||||
|
||||
r.m_vt.m_max.p.x = r.m_r.z;
|
||||
r.m_vt.m_max.p.y = r.m_r.w;
|
||||
@@ -853,7 +917,7 @@ bool GSHwHack::GSC_BlueTongueGames(GSRendererHW& r, int& skip)
|
||||
|
||||
// This is the giant dither-like depth buffer. We need this on the CPU *and* the GPU for textures which are
|
||||
// rendered on both.
|
||||
if (context->FRAME.FBW == 8 && r.m_index.tail == 32 && r.PRIM->TME && context->TEX0.TBW == 1)
|
||||
if (context->FRAME.FBW == 8 && r.m_index->tail == 32 && r.PRIM->TME && context->TEX0.TBW == 1)
|
||||
{
|
||||
r.SwPrimRender(r, false, false);
|
||||
return false;
|
||||
@@ -893,8 +957,8 @@ bool GSHwHack::GSC_MetalGearSolid3(GSRendererHW& r, int& skip)
|
||||
GL_INS("OI_MetalGearSolid3(): %x -> %x, %dx%d, subtract %d", RFBP, RFBP + (RFBW / 2), r.m_r.width(), r.m_r.height(),
|
||||
w_sub);
|
||||
|
||||
for (u32 i = 0; i < r.m_vertex.next; i++)
|
||||
r.m_vertex.buff[i].XYZ.X -= w_sub_fp;
|
||||
for (u32 i = 0; i < r.m_vertex->next; i++)
|
||||
r.m_vertex->buff[i].XYZ.X -= w_sub_fp;
|
||||
|
||||
// No point adjusting the scissor, it just ends up expanding out anyway.. but we do have to fix up the draw rect.
|
||||
r.m_r -= GSVector4i(w_sub);
|
||||
@@ -907,7 +971,7 @@ bool GSHwHack::GSC_Turok(GSRendererHW& r, int& skip)
|
||||
// Since we can't look in to the future to check this, the options are either rearrange all the pages in a target when the width changes
|
||||
// (very slow, could break a ton of stuff which stores different things in the alpha channel), or this. I choose this.
|
||||
|
||||
if (r.m_index.tail == 6 && RPRIM->PRIM == 4 && !RTME && RFBMSK == 0x00FFFFFF && floor(r.m_vt.m_max.p.x) == 512 && r.m_env.CTXT[r.m_backed_up_ctx].FRAME.FBW == 10 && RFRAME.FBW == 8 && RFPSM == PSMCT32 && RTEST.ATE && RTEST.ATST == ATST_GEQUAL)
|
||||
if (r.m_index->tail == 6 && RPRIM->PRIM == 4 && !RTME && RFBMSK == 0x00FFFFFF && floor(r.m_vt.m_max.p.x) == 512 && r.m_env.CTXT[r.m_backed_up_ctx].FRAME.FBW == 10 && RFRAME.FBW == 8 && RFPSM == PSMCT32 && RTEST.ATE && RTEST.ATST == ATST_GEQUAL)
|
||||
{
|
||||
int num_pages = r.m_cached_ctx.FRAME.FBW * ((floor(r.m_vt.m_max.p.y) + 31) / 32);
|
||||
r.m_cached_ctx.FRAME.FBW = 10;
|
||||
@@ -924,7 +988,7 @@ bool GSHwHack::GSC_Turok(GSRendererHW& r, int& skip)
|
||||
|
||||
bool GSHwHack::OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
const u32 n_vertices = r.m_vertex.next;
|
||||
const u32 n_vertices = r.m_vertex->next;
|
||||
const int w = r.m_r.width();
|
||||
const int h = r.m_r.height();
|
||||
const bool is_copy = !r.PRIM->ABE || (
|
||||
@@ -957,7 +1021,7 @@ bool GSHwHack::OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds
|
||||
const u32 FBP = r.m_cached_ctx.FRAME.Block();
|
||||
const u32 FBW = r.m_cached_ctx.FRAME.FBW;
|
||||
GL_INS("PointListPalette - m_r = <%d, %d => %d, %d>, n_vertices = %u, FBP = 0x%x, FBW = %u", r.m_r.x, r.m_r.y, r.m_r.z, r.m_r.w, n_vertices, FBP, FBW);
|
||||
const GSVertex* RESTRICT v = r.m_vertex.buff;
|
||||
const GSVertex* RESTRICT v = r.m_vertex->buff;
|
||||
const int ox(r.m_context->XYOFFSET.OFX);
|
||||
const int oy(r.m_context->XYOFFSET.OFY);
|
||||
for (size_t i = 0; i < n_vertices; ++i)
|
||||
@@ -1155,9 +1219,9 @@ bool GSHwHack::OI_ArTonelico2(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GST
|
||||
buffer to adapt the page width properly.
|
||||
*/
|
||||
|
||||
const GSVertex* v = &r.m_vertex.buff[0];
|
||||
const GSVertex* v = &r.m_vertex->buff[0];
|
||||
|
||||
if (ds && r.m_vertex.next == 2 && !RPRIM->TME && RFRAME.FBW == 10 && v->XYZ.Z == 0 && RTEST.ZTST == ZTST_ALWAYS)
|
||||
if (ds && r.m_vertex->next == 2 && !RPRIM->TME && RFRAME.FBW == 10 && v->XYZ.Z == 0 && RTEST.ZTST == ZTST_ALWAYS)
|
||||
{
|
||||
GL_INS("OI_ArTonelico2");
|
||||
g_gs_device->ClearDepth(ds, 0.0f);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -96,7 +96,7 @@ private:
|
||||
void HandleProvokingVertexFirst();
|
||||
void SetupIA(float target_scale, float sx, float sy, bool req_vert_backup);
|
||||
void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GSTextureCache::Source* tex);
|
||||
bool EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt = nullptr);
|
||||
u32 EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt = nullptr);
|
||||
void EmulateBlending(int rt_alpha_min, int rt_alpha_max, const bool DATE, bool& DATE_PRIMID, bool& DATE_BARRIER, GSTextureCache::Target* rt,
|
||||
bool can_scale_rt_alpha, bool& new_rt_alpha_scale);
|
||||
void CleanupDraw(bool invalidate_temp_src);
|
||||
|
||||
@@ -39,21 +39,21 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc, b
|
||||
GSRasterizerData data;
|
||||
GSScanlineGlobalData& gd = data.global;
|
||||
|
||||
hw.m_sw_vertex_buffer.resize(((hw.m_vertex.next + 1) & ~1));
|
||||
hw.m_sw_vertex_buffer.resize(((hw.m_vertex->next + 1) & ~1));
|
||||
|
||||
data.primclass = vt.m_primclass;
|
||||
data.buff = nullptr;
|
||||
data.vertex = hw.m_sw_vertex_buffer.data();
|
||||
data.vertex_count = hw.m_vertex.next;
|
||||
data.index = hw.m_index.buff;
|
||||
data.index_count = hw.m_index.tail;
|
||||
data.vertex_count = hw.m_vertex->next;
|
||||
data.index = hw.m_index->buff;
|
||||
data.index_count = hw.m_index->tail;
|
||||
data.scanmsk_value = env.SCANMSK.MSK;
|
||||
|
||||
// Skip per pixel division if q is constant.
|
||||
// Optimize the division by 1 with a nop. It also means that GS_SPRITE_CLASS must be processed when !vt.m_eq.q.
|
||||
// If you have both GS_SPRITE_CLASS && vt.m_eq.q, it will depends on the first part of the 'OR'.
|
||||
const u32 q_div = !hw.IsMipMapActive() && ((vt.m_eq.q && vt.m_min.t.z != 1.0f) || (!vt.m_eq.q && vt.m_primclass == GS_SPRITE_CLASS));
|
||||
GSVertexSW::s_cvb[vt.m_primclass][PRIM->TME][PRIM->FST][q_div](context, data.vertex, hw.m_vertex.buff, hw.m_vertex.next);
|
||||
GSVertexSW::s_cvb[vt.m_primclass][PRIM->TME][PRIM->FST][q_div](context, data.vertex, hw.m_vertex->buff, hw.m_vertex->next);
|
||||
|
||||
GSVector4i scissor = context->scissor.in;
|
||||
GSVector4i bbox = GSVector4i(vt.m_min.p.floor().xyxy(vt.m_max.p.ceil())).rintersect(scissor);
|
||||
@@ -524,12 +524,12 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc, b
|
||||
|
||||
const u32 ofx = context->XYOFFSET.OFX;
|
||||
|
||||
for (int i = 0, j = hw.m_vertex.tail; i < j; i++)
|
||||
for (int i = 0, j = hw.m_vertex->tail; i < j; i++)
|
||||
{
|
||||
#if _M_SSE >= 0x501
|
||||
if ((((hw.m_vertex.buff[i].XYZ.X - ofx) + 15) >> 4) & 7) // aligned to 8
|
||||
if ((((hw.m_vertex->buff[i].XYZ.X - ofx) + 15) >> 4) & 7) // aligned to 8
|
||||
#else
|
||||
if ((((hw.m_vertex.buff[i].XYZ.X - ofx) + 15) >> 4) & 3) // aligned to 4
|
||||
if ((((hw.m_vertex->buff[i].XYZ.X - ofx) + 15) >> 4) & 3) // aligned to 4
|
||||
#endif
|
||||
{
|
||||
gd.sel.notest = 0;
|
||||
|
||||
@@ -1059,12 +1059,13 @@ void GSTextureCache::DirtyRectByPage(u32 sbp, u32 spsm, u32 sbw, Target* t, GSVe
|
||||
|
||||
__ri static GSTextureCache::Source* FindSourceInMap(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA,
|
||||
const GSLocalMemory::psm_t& psm_s, const u32* clut, const GSTexture* gpu_clut, const GSVector2i& compare_lod,
|
||||
const GSTextureCache::SourceRegion& region, u32 fixed_tex0, FastList<GSTextureCache::Source*>& map)
|
||||
const GSTextureCache::SourceRegion& region, u32 fixed_tex0, FastList<GSTextureCache::Source*>& map, const GIFRegCLAMP& CLAMP, GSVector4i read_area)
|
||||
{
|
||||
GSTextureCache::Source* best_s = nullptr;
|
||||
|
||||
for (auto i = map.begin(); i != map.end(); ++i)
|
||||
{
|
||||
GSTextureCache::Source* s = *i;
|
||||
|
||||
if (((TEX0.U32[0] ^ s->m_TEX0.U32[0]) | ((TEX0.U32[1] ^ s->m_TEX0.U32[1]) & 3)) != 0) // TBP0 TBW PSM TW TH
|
||||
continue;
|
||||
|
||||
@@ -1094,8 +1095,23 @@ __ri static GSTextureCache::Source* FindSourceInMap(const GIFRegTEX0& TEX0, cons
|
||||
// When fixed tex0 is used, we must find a matching region texture. The base likely
|
||||
// doesn't contain to the correct region. Bit cheeky here, avoid a logical or by
|
||||
// adding the invalid tex0 bit in.
|
||||
if (((s->m_region.bits | fixed_tex0) != 0) && s->m_region.bits != region.bits)
|
||||
continue;
|
||||
|
||||
if (((s->m_region.bits | fixed_tex0) != 0))
|
||||
{
|
||||
const bool is_clamped = CLAMP.WMS == CLAMP_CLAMP && CLAMP.WMT == CLAMP_CLAMP;
|
||||
if (is_clamped && s->m_region.GetMinX() == 0 && s->m_region.GetMinY() == 0)
|
||||
{
|
||||
const GSVector4i read_region = GSVector4i(0, 0, read_area.z, read_area.w);
|
||||
const GSVector4i region_area = GSVector4i(s->m_region.GetMinX(), s->m_region.GetMinY(), s->m_region.HasX() ? s->m_region.GetMaxX() : (1 << s->m_TEX0.TW), s->m_region.HasY() ? s->m_region.GetMaxY() : (1 << s->m_TEX0.TW));
|
||||
|
||||
if (!region_area.rintersect(read_region).eq(read_region))
|
||||
continue;
|
||||
}
|
||||
else if (((s->m_region.bits | fixed_tex0) != 0) && s->m_region.bits != region.bits)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Same base mip texture, but we need to check that MXL was the same as well.
|
||||
// When mipmapping is off, this will be 0,0 vs 0,0.
|
||||
@@ -1107,7 +1123,10 @@ __ri static GSTextureCache::Source* FindSourceInMap(const GIFRegTEX0& TEX0, cons
|
||||
return s;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
if (best_s != nullptr)
|
||||
return best_s;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GSTextureCache::Source* GSTextureCache::LookupDepthSource(const bool is_depth, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, const bool linear, const GIFRegFRAME& frame, bool req_color, bool req_alpha, bool palette)
|
||||
@@ -1127,7 +1146,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const bool is_depth, c
|
||||
const u32* const clut = g_gs_renderer->m_mem.m_clut;
|
||||
GSTexture* const gpu_clut = (psm_s.pal > 0) ? g_gs_renderer->m_mem.m_clut.GetGPUTexture() : nullptr;
|
||||
Source* src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, GSVector2i(0, 0), region,
|
||||
region.IsFixedTEX0(TEX0), m_src.m_map[TEX0.TBP0 >> 5]);
|
||||
region.IsFixedTEX0(TEX0), m_src.m_map[TEX0.TBP0 >> 5], CLAMP, r);
|
||||
if (src)
|
||||
{
|
||||
GL_CACHE("TC: src hit: (0x%x, %s)", TEX0.TBP0, GSUtil::GetPSMName(TEX0.PSM));
|
||||
@@ -1332,10 +1351,10 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
const GSOffset offset(psm_s.info, TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
const u32 region_page = offset.bn(region.GetMinX(), region.GetMinY()) >> 5;
|
||||
if (lookup_page != region_page)
|
||||
src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, compare_lod, region, is_fixed_tex0, m_src.m_map[region_page]);
|
||||
src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, compare_lod, region, is_fixed_tex0, m_src.m_map[region_page], CLAMP, r);
|
||||
}
|
||||
if (!src)
|
||||
src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, compare_lod, region, is_fixed_tex0, m_src.m_map[lookup_page]);
|
||||
src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, compare_lod, region, is_fixed_tex0, m_src.m_map[lookup_page], CLAMP, r);
|
||||
|
||||
if (src && src->m_from_target && GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::MergeTargets && GSLocalMemory::GetUnwrappedEndBlockAddress(TEX0.TBP0, TEX0.TBW, TEX0.PSM, r) > src->m_from_target->m_end_block)
|
||||
{
|
||||
@@ -1703,7 +1722,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
if (found_t && (bw != t->m_TEX0.TBW || t->m_TEX0.PSM != psm))
|
||||
match = false;
|
||||
|
||||
//if (!t_clean && can_convert)
|
||||
// Different swizzle, different width, and dirty, so probably not what we want.
|
||||
// DevCon.Warning("Expected %x Got %x shuffle %d draw %d", psm, t_psm, possible_shuffle, GSState::s_n);
|
||||
if (match)
|
||||
{
|
||||
@@ -1769,8 +1788,10 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
(GSLocalMemory::m_psm[color_psm].bpp >= 16 || (/*possible_shuffle &&*/ GSLocalMemory::m_psm[color_psm].bpp == 8 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp >= 16)) && // Channel shuffles or non indexed lookups.
|
||||
t->m_age <= 1 && (!found_t || t->m_last_draw > dst->m_last_draw) /*&& CanTranslate(bp, bw, psm, block_boundary_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW)*/)
|
||||
{
|
||||
const u32 end_block = GSLocalMemory::GetEndBlockAddress(bp, TEX0.TBW, TEX0.PSM, r);
|
||||
const u32 adj_bp = (end_block < t->m_TEX0.TBP0 && t->UnwrappedEndBlock() > GS_MAX_BLOCKS) ? (bp + GS_MAX_BLOCKS) : bp;
|
||||
u32 rt_tbw = std::max(1U, t->m_TEX0.TBW);
|
||||
u32 horz_page_offset = ((bp - t->m_TEX0.TBP0) >> 5) % rt_tbw;
|
||||
u32 horz_page_offset = ((adj_bp - t->m_TEX0.TBP0) >> 5) % rt_tbw;
|
||||
|
||||
if (GSLocalMemory::m_psm[psm].bpp == GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp && bw != rt_tbw && block_boundary_rect.height() > GSLocalMemory::m_psm[psm].pgs.y)
|
||||
continue;
|
||||
@@ -1783,7 +1804,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
((t->m_TEX0.TBW < (horz_page_offset + ((block_boundary_rect.z + GSLocalMemory::m_psm[psm].pgs.x - 1) / GSLocalMemory::m_psm[psm].pgs.x)) ||
|
||||
(t->m_TEX0.TBW != bw && block_boundary_rect.w > GSLocalMemory::m_psm[psm].pgs.y))))
|
||||
{
|
||||
DbgCon.Warning("BP %x - 16bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
DbgCon.Warning("BP %x - 16bit bad match for target bp %x bw %d src %d format %d", adj_bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
continue;
|
||||
}
|
||||
// Keep note that 2 bw is basically 1 normal page, as bw is in 64 pixels, and 8bit pages are 128 pixels wide, aka 2 bw.
|
||||
@@ -1795,7 +1816,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) <= t->m_TEX0.TBW) &&
|
||||
!(((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) == rt_tbw)))))
|
||||
{
|
||||
DbgCon.Warning("BP %x - 8bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
DbgCon.Warning("BP %x - 8bit bad match for target bp %x bw %d src %d format %d", adj_bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
continue;
|
||||
}
|
||||
else if (!possible_shuffle && GSLocalMemory::m_psm[psm].bpp <= 8 && TEX0.TBW == 1)
|
||||
@@ -1833,16 +1854,16 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
else // Formats are not compatible for normal draws, only shuffles.
|
||||
continue;
|
||||
}
|
||||
if (bp > t->m_TEX0.TBP0)
|
||||
if (adj_bp > t->m_TEX0.TBP0)
|
||||
{
|
||||
if (!region.HasEither() && GSLocalMemory::m_psm[psm].bpp == 32 && (t->m_TEX0.TBW - (((bp - t->m_TEX0.TBP0) >> 5) % rt_tbw)) < static_cast<u32>((block_boundary_rect.width() + 63) / 64))
|
||||
if (!region.HasEither() && GSLocalMemory::m_psm[psm].bpp == 32 && (t->m_TEX0.TBW - (((adj_bp - t->m_TEX0.TBP0) >> 5) % rt_tbw)) < static_cast<u32>((block_boundary_rect.width() + 63) / 64))
|
||||
{
|
||||
DbgCon.Warning("Bad alignmenet");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure it's inside if not a shuffle, sometimes valid areas can get messy, like TOCA Race Driver 2 where it goes over to 480, but it's rounded up to 512 in the shuffle.
|
||||
if (!possible_shuffle && !t->Inside(bp, bw, psm, block_boundary_rect))
|
||||
if (!possible_shuffle && !t->Inside(adj_bp, bw, psm, block_boundary_rect))
|
||||
continue;
|
||||
|
||||
GSVector4i new_rect = (GSLocalMemory::m_psm[color_psm].bpp != GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp && (psm & 0x7) != PSMCT16) ? block_boundary_rect : rect;
|
||||
@@ -1852,7 +1873,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
// Hitman Blood Money is an example of this in the theatre.
|
||||
const u32 rt_tbw = (possible_shuffle || bw == 1 || GSUtil::GetChannelMask(psm) != 0x8 || frame.FBW <= bw || frame.FBW == t->m_TEX0.TBW || bw == t->m_TEX0.TBW) ? t->m_TEX0.TBW : frame.FBW;
|
||||
|
||||
const bool can_translate = CanTranslate(bp, bw, src_psm, new_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, rt_tbw);
|
||||
const bool can_translate = CanTranslate(adj_bp, bw, src_psm, new_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, rt_tbw);
|
||||
if (can_translate)
|
||||
{
|
||||
const bool swizzle_match = GSLocalMemory::m_psm[src_psm].depth == GSLocalMemory::m_psm[t->m_TEX0.PSM].depth;
|
||||
@@ -1862,7 +1883,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
|
||||
if (swizzle_match)
|
||||
{
|
||||
rect = TranslateAlignedRectByPage(t->m_TEX0.TBP0, t->m_end_block, rt_tbw, t->m_TEX0.PSM, t->m_valid, bp, src_psm, bw, new_rect);
|
||||
rect = TranslateAlignedRectByPage(t->m_TEX0.TBP0, t->m_end_block, rt_tbw, t->m_TEX0.PSM, t->m_valid, adj_bp, src_psm, bw, new_rect);
|
||||
rect.x -= new_rect.x;
|
||||
rect.y -= new_rect.y;
|
||||
}
|
||||
@@ -1882,7 +1903,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
new_rect.z = (new_rect.z + (page_size.x - 1)) & ~(page_size.x - 1);
|
||||
new_rect.w = (new_rect.w + (page_size.y - 1)) & ~(page_size.y - 1);
|
||||
}
|
||||
rect = TranslateAlignedRectByPage(t, bp & ~((1 << 5) - 1), src_psm, bw, new_rect);
|
||||
rect = TranslateAlignedRectByPage(t, adj_bp & ~((1 << 5) - 1), src_psm, bw, new_rect);
|
||||
rect.x -= new_rect.x & ~(page_size.x - 1);
|
||||
rect.y -= new_rect.y & ~(page_size.y - 1);
|
||||
}
|
||||
@@ -1914,7 +1935,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
}
|
||||
else
|
||||
{
|
||||
SurfaceOffset so = ComputeSurfaceOffset(bp, bw, src_psm, new_rect, t);
|
||||
SurfaceOffset so = ComputeSurfaceOffset(adj_bp, bw, src_psm, new_rect, t);
|
||||
if (!so.is_valid && t->Wraps())
|
||||
{
|
||||
// Improves Beyond Good & Evil shadow.
|
||||
@@ -2186,7 +2207,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
}
|
||||
}
|
||||
|
||||
src = CreateSource(src_TEX0, TEXA, dst, x_offset, y_offset, lod, &rect, gpu_clut, region, target_bp_hit_outside_valid_area && TEX0.PSM != PSMT8);
|
||||
src = CreateSource(src_TEX0, TEXA, CLAMP, dst, x_offset, y_offset, lod, &rect, gpu_clut, region, target_bp_hit_outside_valid_area && TEX0.PSM != PSMT8);
|
||||
if (!src) [[unlikely]]
|
||||
return nullptr;
|
||||
}
|
||||
@@ -2294,10 +2315,10 @@ void GSTextureCache::CombineAlignedInsideTargets(Target* target, GSTextureCache:
|
||||
continue;
|
||||
}
|
||||
// Formats match
|
||||
if (t->m_TEX0.TBW == target->m_TEX0.TBW && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == GSLocalMemory::m_psm[target->m_TEX0.PSM].bpp)
|
||||
if ((t->m_TEX0.TBW == target->m_TEX0.TBW || t->m_TEX0.TBW == 1) && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == GSLocalMemory::m_psm[target->m_TEX0.PSM].bpp)
|
||||
{
|
||||
const GSLocalMemory::psm_t& t_psm = GSLocalMemory::m_psm[t->m_TEX0.PSM];
|
||||
const u32 page_offset = ((t->m_TEX0.TBP0 - target->m_TEX0.TBP0) >> 5) % std::max(1U, t->m_TEX0.TBW);
|
||||
const GSLocalMemory::psm_t& t_psm = GSLocalMemory::m_psm[target->m_TEX0.PSM];
|
||||
const u32 page_offset = ((t->m_TEX0.TBP0 - target->m_TEX0.TBP0) >> 5) % std::max(1U, target->m_TEX0.TBW);
|
||||
const u32 page_width = (t->m_valid.z + (t_psm.pgs.x - 1)) / t_psm.pgs.x;
|
||||
|
||||
if ((page_offset + page_width) <= target->m_TEX0.TBW)
|
||||
@@ -2308,7 +2329,7 @@ void GSTextureCache::CombineAlignedInsideTargets(Target* target, GSTextureCache:
|
||||
{
|
||||
t->Update();
|
||||
|
||||
const u32 vertical_offset = (((t->m_TEX0.TBP0 - target->m_TEX0.TBP0) >> 5) / std::max(1U, t->m_TEX0.TBW)) * t_psm.pgs.y;
|
||||
const u32 vertical_offset = (((t->m_TEX0.TBP0 - target->m_TEX0.TBP0) >> 5) / std::max(1U, target->m_TEX0.TBW)) * t_psm.pgs.y;
|
||||
const u32 horizontal_offset = page_offset * t_psm.pgs.x;
|
||||
const GSVector4i target_drect_unscaled = t->m_drawn_since_read + GSVector4i(horizontal_offset, vertical_offset).xyxy();
|
||||
|
||||
@@ -2673,10 +2694,12 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
for (auto i = list.begin(); i != list.end(); ++i)
|
||||
{
|
||||
Target* t = *i;
|
||||
const u32 end_block = GSLocalMemory::GetEndBlockAddress(bp, TEX0.TBW, TEX0.PSM, GSVector4i(0, size.y, size.x, size.y + 1));
|
||||
const u32 bp_adj = (end_block < t->m_TEX0.TBP0 && t->UnwrappedEndBlock() > GS_MAX_BLOCKS) ? (bp + GS_MAX_BLOCKS) : bp;
|
||||
const bool half_buffer_match = GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets && TEX0.TBW == t->m_TEX0.TBW && TEX0.PSM == t->m_TEX0.PSM &&
|
||||
bp == GSLocalMemory::GetStartBlockAddress(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, GSVector4i(0, size.y, size.x, size.y + 1));
|
||||
// Make sure the target is inside the texture
|
||||
if (t->m_TEX0.TBP0 <= bp && bp <= t->m_end_block && (half_buffer_match || t->Inside(bp, TEX0.TBW, TEX0.PSM, GSVector4i::loadh(size))))
|
||||
if (t->m_TEX0.TBP0 <= bp_adj && bp_adj <= t->UnwrappedEndBlock() && (half_buffer_match || t->Inside(bp_adj, TEX0.TBW, TEX0.PSM, GSVector4i::loadh(size))))
|
||||
{
|
||||
if (dst && (GSState::s_n - dst->m_last_draw) < (GSState::s_n - t->m_last_draw))
|
||||
continue;
|
||||
@@ -2748,7 +2771,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
dst->m_TEX0.TBP0, dst->m_TEX0.TBW, GSUtil::GetPSMName(dst->m_TEX0.PSM));
|
||||
}
|
||||
|
||||
if (dst->m_scale != scale && (!preserve_scale || is_shuffle || !dst->m_downscaled || TEX0.TBW != dst->m_TEX0.TBW))
|
||||
if (dst->m_scale != scale && (!preserve_scale || (type == RenderTarget && (is_shuffle || !dst->m_downscaled || TEX0.TBW != dst->m_TEX0.TBW))))
|
||||
{
|
||||
calcRescale(dst);
|
||||
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) :
|
||||
@@ -2756,7 +2779,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
if (!tex)
|
||||
return nullptr;
|
||||
|
||||
if (scale == 1.0f)
|
||||
if (scale == 1.0f && type == RenderTarget)
|
||||
{
|
||||
// When using native HPO, the top-left column/row of pixels are often not drawn. Clamp these away to avoid sampling black,
|
||||
// causing bleeding into the edges of the downsampled texture.
|
||||
@@ -2770,7 +2793,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
g_gs_device->FilteredDownsampleTexture(dst->m_texture, tex, downsample_factor, clamp_min, dRect);
|
||||
}
|
||||
else
|
||||
g_gs_device->StretchRect(dst->m_texture, sRect, tex, dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, dst->m_scale < scale);
|
||||
g_gs_device->StretchRect(dst->m_texture, sRect, tex, dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, type == RenderTarget && !preserve_scale);
|
||||
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
m_target_memory_usage = (m_target_memory_usage - dst->m_texture->GetMemUsage()) + tex->GetMemUsage();
|
||||
@@ -3796,6 +3819,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
}
|
||||
|
||||
const int height_adjust = ((((dst_end_block + 31) - t->m_TEX0.TBP0) >> 5) / std::max(t->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.y;
|
||||
bool delete_target = true;
|
||||
|
||||
if (height_adjust < t->m_unscaled_size.y)
|
||||
{
|
||||
@@ -3803,27 +3827,32 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
t->m_valid.w -= height_adjust;
|
||||
t->ResizeValidity(t->m_valid);
|
||||
|
||||
GSTexture* tex = (t->m_type == RenderTarget) ?
|
||||
g_gs_device->CreateRenderTarget(t->m_texture->GetWidth(), t->m_texture->GetHeight(), GSTexture::Format::Color, true) :
|
||||
g_gs_device->CreateDepthStencil(t->m_texture->GetWidth(), t->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true);
|
||||
if (tex)
|
||||
if (!t->m_valid.rempty())
|
||||
{
|
||||
g_gs_device->CopyRect(t->m_texture, tex, GSVector4i(0, height_adjust * t->m_scale, t->m_texture->GetWidth(), t->m_texture->GetHeight()), 0, 0);
|
||||
if (src && src->m_target && src->m_from_target == t)
|
||||
delete_target = false;
|
||||
GSTexture* tex = (t->m_type == RenderTarget) ?
|
||||
g_gs_device->CreateRenderTarget(t->m_texture->GetWidth(), t->m_texture->GetHeight(), GSTexture::Format::Color, true) :
|
||||
g_gs_device->CreateDepthStencil(t->m_texture->GetWidth(), t->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true);
|
||||
if (tex)
|
||||
{
|
||||
src->m_from_target = t;
|
||||
src->m_texture = t->m_texture;
|
||||
src->m_target_direct = false;
|
||||
src->m_shared_texture = false;
|
||||
g_gs_device->CopyRect(t->m_texture, tex, GSVector4i(0, height_adjust * t->m_scale, t->m_texture->GetWidth(), t->m_texture->GetHeight()), 0, 0);
|
||||
if (src && src->m_target && src->m_from_target == t)
|
||||
{
|
||||
src->m_from_target = t;
|
||||
src->m_texture = t->m_texture;
|
||||
src->m_target_direct = false;
|
||||
src->m_shared_texture = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_gs_device->Recycle(t->m_texture);
|
||||
}
|
||||
t->m_texture = tex;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_gs_device->Recycle(t->m_texture);
|
||||
}
|
||||
t->m_texture = tex;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (delete_target)
|
||||
{
|
||||
if (src && src->m_target && src->m_from_target == t)
|
||||
{
|
||||
@@ -4281,23 +4310,27 @@ bool GSTextureCache::PrepareDownloadTexture(u32 width, u32 height, GSTexture::Fo
|
||||
}
|
||||
}
|
||||
}*/
|
||||
void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm, u32 write_bw)
|
||||
void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm, u32 write_bw, u32 fb_mask, bool ignore_exact)
|
||||
{
|
||||
const bool preserve_alpha = (GSLocalMemory::m_psm[write_psm].trbpp == 24);
|
||||
for (int type = 0; type < 2; type++)
|
||||
const bool preserve_alpha = (GSLocalMemory::m_psm[write_psm].trbpp == 24) || (fb_mask & 0xFF000000);
|
||||
for (int type = 0; type < (ignore_exact ? 1 : 2); type++)
|
||||
{
|
||||
auto& list = m_dst[type];
|
||||
for (auto i = list.begin(); i != list.end();)
|
||||
{
|
||||
Target* const t = *i;
|
||||
if (start_bp != t->m_TEX0.TBP0 && (t->m_TEX0.TBP0 > end_bp || t->UnwrappedEndBlock() < start_bp))
|
||||
|
||||
if ((ignore_exact && start_bp == t->m_TEX0.TBP0) || (start_bp != t->m_TEX0.TBP0 && (t->m_TEX0.TBP0 > end_bp || t->UnwrappedEndBlock() < start_bp)))
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool compatible_fmt = GSUtil::HasCompatibleBits(t->m_TEX0.PSM, write_psm);
|
||||
const bool compatible_width = std::max(t->m_TEX0.TBW, 1U) == std::max(write_bw, 1U);
|
||||
|
||||
// If not fully contained but they are aligned and or clean, just dirty the area.
|
||||
if (type != DepthStencil && start_bp != t->m_TEX0.TBP0 && (t->m_TEX0.TBP0 < start_bp || t->UnwrappedEndBlock() > end_bp))
|
||||
if ((type != DepthStencil || !compatible_fmt || !compatible_width) && start_bp != t->m_TEX0.TBP0 && (t->m_TEX0.TBP0 < start_bp || t->UnwrappedEndBlock() > end_bp))
|
||||
{
|
||||
const u32 offset = (std::abs(static_cast<int>(start_bp - t->m_TEX0.TBP0)) >> 5) % std::max(1U, t->m_TEX0.TBW);
|
||||
const GSVector4i dirty_rect = t->m_dirty.GetTotalRect(t->m_TEX0, t->m_unscaled_size).rintersect(t->m_valid);
|
||||
@@ -4313,7 +4346,7 @@ void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 wr
|
||||
{
|
||||
|
||||
RGBAMask mask;
|
||||
mask._u32 = GSUtil::GetChannelMask(write_psm);
|
||||
mask._u32 = GSUtil::GetChannelMask(write_psm, fb_mask);
|
||||
AddDirtyRectTarget(t, invalidate_r, t->m_TEX0.PSM, t->m_TEX0.TBW, mask, false);
|
||||
}
|
||||
|
||||
@@ -4343,7 +4376,7 @@ void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 wr
|
||||
|
||||
t->m_valid_alpha_low &= preserve_alpha;
|
||||
t->m_valid_alpha_high &= preserve_alpha;
|
||||
t->m_valid_rgb = false;
|
||||
t->m_valid_rgb &= (fb_mask & 0x00FFFFFF) != 0;
|
||||
|
||||
// Don't keep partial depth buffers around.
|
||||
if ((!t->m_valid_alpha_low && !t->m_valid_alpha_high && !t->m_valid_rgb) || type == DepthStencil)
|
||||
@@ -4365,6 +4398,16 @@ void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 wr
|
||||
delete t;
|
||||
continue;
|
||||
}
|
||||
else if (ignore_exact && GSUtil::HasCompatibleBits(t->m_TEX0.PSM, write_psm))
|
||||
{
|
||||
RGBAMask mask;
|
||||
mask._u32 = GSUtil::GetChannelMask(write_psm, fb_mask);
|
||||
|
||||
AddDirtyRectTarget(t, t->m_valid, t->m_TEX0.PSM, t->m_TEX0.TBW, mask, false);
|
||||
t->m_valid_rgb |= !!(mask._u32 & 0x7);
|
||||
t->m_valid_alpha_low |= mask.c.a;
|
||||
t->m_valid_alpha_high |= mask.c.a;
|
||||
}
|
||||
|
||||
GL_CACHE("TC: InvalidateContainedTargets: Clear RGB valid on %s[%x, %s]", to_string(type), t->m_TEX0.TBP0, GSUtil::GetPSMName(t->m_TEX0.PSM));
|
||||
++i;
|
||||
@@ -4838,7 +4881,10 @@ void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r
|
||||
{
|
||||
if (swizzle_match)
|
||||
{
|
||||
targetr = TranslateAlignedRectByPage(t, bp, psm, bw, r, true);
|
||||
if (exact_bp && GSUtil::HasSameSwizzleBits(psm, t->m_TEX0.PSM) && bw == t->m_TEX0.TBW)
|
||||
targetr = r;
|
||||
else
|
||||
targetr = TranslateAlignedRectByPage(t, bp, psm, bw, r, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5733,10 +5779,7 @@ void GSTextureCache::ReplaceSourceTexture(Source* s, GSTexture* new_texture, flo
|
||||
if (s->m_from_hash_cache)
|
||||
s->m_from_hash_cache->refcount++;
|
||||
else if (!s->m_shared_texture)
|
||||
{
|
||||
DevCon.Warning("replace %d", m_source_memory_usage);
|
||||
m_source_memory_usage += s->m_texture->GetMemUsage();
|
||||
}
|
||||
}
|
||||
|
||||
void GSTextureCache::IncAge()
|
||||
@@ -5816,7 +5859,7 @@ void GSTextureCache::IncAge()
|
||||
}
|
||||
|
||||
//Fixme: Several issues in here. Not handling depth stencil, pitch conversion doesnt work.
|
||||
GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* dst, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region, bool force_temp)
|
||||
GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, Target* dst, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region, bool force_temp)
|
||||
{
|
||||
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM];
|
||||
Source* src = new Source(TEX0, TEXA);
|
||||
@@ -6296,6 +6339,41 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
m_temporary_source = src;
|
||||
}
|
||||
|
||||
// We can check for a recent upload to see if we can find out out what the actual size is.
|
||||
if (!region.HasEither() && m_temporary_source == nullptr && CLAMP.WMS == CLAMP_CLAMP && CLAMP.WMT == CLAMP_CLAMP)
|
||||
{
|
||||
if (src_range->z < tw && src_range->w < th)
|
||||
{
|
||||
auto& transfers = GSRendererHW::GetInstance()->m_draw_transfers;
|
||||
|
||||
if (transfers.size() > 0)
|
||||
{
|
||||
const int last_draw = transfers.back().draw;
|
||||
|
||||
for (auto iter = transfers.rbegin(); iter != transfers.rend(); ++iter)
|
||||
{
|
||||
if (last_draw - iter->draw > 10)
|
||||
break;
|
||||
|
||||
// If the format, and location doesn't overlap
|
||||
if (iter->blit.DBP == TEX0.TBP0 && iter->blit.DBW == TEX0.TBW && iter->blit.DPSM == TEX0.PSM)
|
||||
{
|
||||
const int new_max_x = std::min(tw, std::max(iter->rect.z, Common::AlignUpPow2(src_range->z, psm.pgs.x)));
|
||||
const int new_max_y = std::min(th, std::max(iter->rect.w, Common::AlignUpPow2(src_range->w, psm.pgs.y)));
|
||||
|
||||
if (new_max_x != tw && new_max_y != th)
|
||||
{
|
||||
region.SetX(0, new_max_x);
|
||||
region.SetY(0, new_max_y);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// maintain the clut even when paltex is on for the dump/replacement texture lookup
|
||||
bool paltex = (GSConfig.GPUPaletteConversion && psm.pal > 0) || gpu_clut;
|
||||
const u32* clut = (psm.pal > 0) ? static_cast<const u32*>(g_gs_renderer->m_mem.m_clut) : nullptr;
|
||||
@@ -7923,7 +8001,7 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca
|
||||
// Can't do partial copies in DirectX for depth textures, and it's probably not ideal in other
|
||||
// APIs either. So use a fullscreen quad setting depth instead.
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::DEPTH_COPY, false);
|
||||
g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::DEPTH_COPY, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -8650,6 +8728,7 @@ GSTextureCache::SourceRegion GSTextureCache::SourceRegion::Create(GIFRegTEX0 TEX
|
||||
GL_CACHE("TC: Region repeat optimization: %d width -> %d", 1 << TEX0.TW, region.GetWidth());
|
||||
}
|
||||
}
|
||||
|
||||
if (CLAMP.WMT == CLAMP_REGION_CLAMP && CLAMP.MAXV >= CLAMP.MINV)
|
||||
{
|
||||
const u32 rh = CLAMP.MAXV - CLAMP.MINV + 1;
|
||||
|
||||
@@ -32,8 +32,18 @@ public:
|
||||
|
||||
constexpr static bool CheckOverlap(const u32 a_bp, const u32 a_bp_end, const u32 b_bp, const u32 b_bp_end) noexcept
|
||||
{
|
||||
const bool valid = a_bp <= a_bp_end && b_bp <= b_bp_end;
|
||||
const bool overlap = a_bp <= b_bp_end && a_bp_end >= b_bp;
|
||||
u32 b_bp_start_synced = b_bp;
|
||||
u32 b_bp_end_synced = b_bp_end;
|
||||
|
||||
// Check for wrapping
|
||||
if (a_bp_end > GS_MAX_BLOCKS && b_bp_end < a_bp)
|
||||
{
|
||||
b_bp_start_synced += GS_MAX_BLOCKS;
|
||||
b_bp_end_synced += GS_MAX_BLOCKS;
|
||||
}
|
||||
|
||||
const bool valid = a_bp <= a_bp_end && b_bp_start_synced <= b_bp_end_synced;
|
||||
const bool overlap = a_bp <= b_bp_end_synced && a_bp_end >= b_bp_start_synced;
|
||||
return valid && overlap;
|
||||
}
|
||||
|
||||
@@ -268,7 +278,7 @@ public:
|
||||
void UpdateValidChannels(u32 psm, u32 fbmsk);
|
||||
|
||||
/// Resizes target texture, DOES NOT RESCALE.
|
||||
bool ResizeTexture(int new_unscaled_width, int new_unscaled_height, bool recycle_old = true, bool require_offset = false, GSVector4i offset = GSVector4i::zero(), bool keep_old = false);
|
||||
bool ResizeTexture(int new_unscaled_width, int new_unscaled_height, bool recycle_old = true, bool require_new_rect = false, GSVector4i new_rect = GSVector4i::zero(), bool keep_old = false);
|
||||
|
||||
private:
|
||||
void UpdateTextureDebugName();
|
||||
@@ -445,7 +455,7 @@ protected:
|
||||
std::unique_ptr<GSDownloadTexture> m_uint16_download_texture;
|
||||
std::unique_ptr<GSDownloadTexture> m_uint32_download_texture;
|
||||
|
||||
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region, bool force_temporary = false);
|
||||
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, Target* t, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region, bool force_temporary = false);
|
||||
|
||||
bool PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size, bool is_frame,
|
||||
bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, GSTextureCache::Source* src = nullptr);
|
||||
@@ -522,7 +532,7 @@ public:
|
||||
bool HasTargetInHeightCache(u32 bp, u32 fbw, u32 psm, u32 max_age = std::numeric_limits<u32>::max(), bool move_front = true);
|
||||
bool Has32BitTarget(u32 bp);
|
||||
|
||||
void InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm = PSMCT32, u32 write_bw = 1);
|
||||
void InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm = PSMCT32, u32 write_bw = 1, u32 fb_mask = 0x00000000, bool ignore_exact = false);
|
||||
void InvalidateVideoMemType(int type, u32 bp, u32 write_psm = PSMCT32, u32 write_fbmsk = 0, bool dirty_only = false);
|
||||
void InvalidateVideoMemSubTarget(GSTextureCache::Target* rt);
|
||||
void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool target = true);
|
||||
|
||||
@@ -2081,6 +2081,7 @@ static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, HalfTexel) == of
|
||||
static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, MinMax) == offsetof(GSMTLMainPSUniform, uv_min_max));
|
||||
static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, STRange) == offsetof(GSMTLMainPSUniform, st_range));
|
||||
static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, ChannelShuffle) == offsetof(GSMTLMainPSUniform, channel_shuffle));
|
||||
static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, ChannelShuffleOffset) == offsetof(GSMTLMainPSUniform, channel_shuffle_offset));
|
||||
static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, TCOffsetHack) == offsetof(GSMTLMainPSUniform, tc_offset));
|
||||
static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, STScale) == offsetof(GSMTLMainPSUniform, st_scale));
|
||||
static_assert(offsetof(GSHWDrawConfig::PSConstantBuffer, DitherMatrix) == offsetof(GSMTLMainPSUniform, dither_matrix));
|
||||
|
||||
@@ -129,6 +129,7 @@ struct GSMTLMainPSUniform
|
||||
unsigned int green_mask;
|
||||
unsigned int green_shift;
|
||||
} channel_shuffle;
|
||||
vector_float2 channel_shuffle_offset;
|
||||
vector_float2 tc_offset;
|
||||
vector_float2 st_scale;
|
||||
matrix_float4x4 dither_matrix;
|
||||
|
||||
@@ -509,7 +509,7 @@ struct PSMain
|
||||
|
||||
uint fetch_raw_depth()
|
||||
{
|
||||
return tex_depth.read(ushort2(in.p.xy)) * 0x1p32f;
|
||||
return tex_depth.read(ushort2(in.p.xy + cb.channel_shuffle_offset)) * 0x1p32f;
|
||||
}
|
||||
|
||||
float4 fetch_raw_color()
|
||||
@@ -517,7 +517,7 @@ struct PSMain
|
||||
if (PS_TEX_IS_FB)
|
||||
return current_color;
|
||||
else
|
||||
return tex.read(ushort2(in.p.xy));
|
||||
return tex.read(ushort2(in.p.xy + cb.channel_shuffle_offset));
|
||||
}
|
||||
|
||||
float4 fetch_c(ushort2 uv)
|
||||
@@ -790,7 +790,7 @@ struct PSMain
|
||||
void fog(thread float4& C, float f)
|
||||
{
|
||||
if (PS_FOG)
|
||||
C.rgb = trunc(mix(cb.fog_color, C.rgb, f));
|
||||
C.rgb = trunc(mix(cb.fog_color, C.rgb, (f * 255.0f) / 256.0f));
|
||||
}
|
||||
|
||||
float4 ps_color()
|
||||
|
||||
@@ -320,14 +320,14 @@ void GSRendererSW::RewriteVerticesIfSTOverflow()
|
||||
constexpr int n = GSUtil::GetClassVertexCount(primclass);
|
||||
|
||||
// Make sure the copy buffer is large enough.
|
||||
while (m_vertex.maxcount < m_index.tail)
|
||||
while (m_vertex->maxcount < m_index->tail)
|
||||
GrowVertexBuffer();
|
||||
|
||||
GSVertex* RESTRICT vertex = m_vertex.buff;
|
||||
GSVertex* RESTRICT vertex_copy = m_vertex.buff_copy;
|
||||
u16* RESTRICT index = m_index.buff;
|
||||
GSVertex* RESTRICT vertex = m_vertex->buff;
|
||||
GSVertex* RESTRICT vertex_copy = m_vertex->buff_copy;
|
||||
u16* RESTRICT index = m_index->buff;
|
||||
|
||||
for (int i = 0; i < static_cast<int>(m_index.tail); i += n)
|
||||
for (int i = 0; i < static_cast<int>(m_index->tail); i += n)
|
||||
{
|
||||
GSVector4 stcq[n];
|
||||
|
||||
@@ -381,18 +381,18 @@ void GSRendererSW::RewriteVerticesIfSTOverflow()
|
||||
}
|
||||
|
||||
// Swap the buffers and fix the counts.
|
||||
std::swap(m_vertex.buff, m_vertex.buff_copy);
|
||||
m_vertex.head = m_vertex.next = m_vertex.tail = m_index.tail;
|
||||
std::swap(m_vertex->buff, m_vertex->buff_copy);
|
||||
m_vertex->head = m_vertex->next = m_vertex->tail = m_index->tail;
|
||||
|
||||
// Recalculate ST min/max/eq in the vertex trace.
|
||||
GSVector4 tmin = GSVector4::cxpr(FLT_MAX);
|
||||
GSVector4 tmax = GSVector4::cxpr(-FLT_MAX);
|
||||
for (int i = 0; i < static_cast<int>(m_index.tail); i += n)
|
||||
for (int i = 0; i < static_cast<int>(m_index->tail); i += n)
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
GSVector4 stcq = GSVector4::cast(GSVector4i(m_vertex.buff[i + j].m[0]));
|
||||
const float Q = (primclass == GS_SPRITE_CLASS) ? stcq.w : m_vertex.buff[i + 1].RGBAQ.Q;
|
||||
GSVector4 stcq = GSVector4::cast(GSVector4i(m_vertex->buff[i + j].m[0]));
|
||||
const float Q = (primclass == GS_SPRITE_CLASS) ? stcq.w : m_vertex->buff[i + 1].RGBAQ.Q;
|
||||
stcq = (stcq / Q).xyzw(stcq);
|
||||
|
||||
tmin = tmin.min(stcq);
|
||||
@@ -451,11 +451,11 @@ void GSRendererSW::Draw()
|
||||
SharedData* sd = static_cast<SharedData*>(data.get());
|
||||
|
||||
sd->primclass = m_vt.m_primclass;
|
||||
sd->buff = (u8*)m_vertex_heap.alloc(sizeof(GSVertexSW) * ((m_vertex.next + 1) & ~1) + sizeof(u32) * m_index.tail, 64);
|
||||
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 = (u16*)(sd->buff + sizeof(GSVertexSW) * ((m_vertex.next + 1) & ~1));
|
||||
sd->index_count = m_index.tail;
|
||||
sd->vertex_count = m_vertex->next;
|
||||
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;
|
||||
|
||||
// skip per pixel division if q is constant.
|
||||
@@ -463,9 +463,9 @@ void GSRendererSW::Draw()
|
||||
// If you have both GS_SPRITE_CLASS && m_vt.m_eq.q, it will depends on the first part of the 'OR'
|
||||
u32 q_div = !IsMipMapActive() && ((m_vt.m_eq.q && m_vt.m_min.t.z != 1.0f) || (!m_vt.m_eq.q && m_vt.m_primclass == GS_SPRITE_CLASS));
|
||||
|
||||
GSVertexSW::s_cvb[m_vt.m_primclass][PRIM->TME][PRIM->FST][q_div](m_context, sd->vertex, m_vertex.buff, m_vertex.next);
|
||||
GSVertexSW::s_cvb[m_vt.m_primclass][PRIM->TME][PRIM->FST][q_div](m_context, sd->vertex, m_vertex->buff, m_vertex->next);
|
||||
|
||||
std::memcpy(sd->index, m_index.buff, sizeof(u16) * m_index.tail);
|
||||
std::memcpy(sd->index, m_index->buff, sizeof(u16) * m_index->tail);
|
||||
|
||||
GSVector4i scissor = context->scissor.in;
|
||||
GSVector4i bbox = GSVector4i(m_vt.m_min.p.floor().upld(m_vt.m_max.p.floor())) + GSVector4i(0, 0, 1, 1); // right/bottom should be exclusive so +1
|
||||
@@ -485,12 +485,12 @@ void GSRendererSW::Draw()
|
||||
{
|
||||
int n = GSUtil::GetVertexCount(PRIM->PRIM);
|
||||
|
||||
for (u32 i = 0, j = 0; i < m_index.tail; i += n, j++)
|
||||
for (u32 i = 0, j = 0; i < m_index->tail; i += n, j++)
|
||||
{
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
GSVertex* v = &m_vertex.buff[m_index.buff[i + k]];
|
||||
GSVertex* vn = &m_vertex.buff[m_index.buff[i + n - 1]];
|
||||
GSVertex* v = &m_vertex->buff[m_index->buff[i + k]];
|
||||
GSVertex* vn = &m_vertex->buff[m_index->buff[i + n - 1]];
|
||||
|
||||
fprintf(s_fp, "%d:%d %f %f %f %f\n",
|
||||
j, k,
|
||||
@@ -1505,12 +1505,12 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
|
||||
|
||||
u32 ofx = context->XYOFFSET.OFX;
|
||||
|
||||
for (int i = 0, j = m_vertex.tail; i < j; i++)
|
||||
for (int i = 0, j = m_vertex->tail; i < j; i++)
|
||||
{
|
||||
#if _M_SSE >= 0x501
|
||||
if ((((m_vertex.buff[i].XYZ.X - ofx) + 15) >> 4) & 7) // aligned to 8
|
||||
if ((((m_vertex->buff[i].XYZ.X - ofx) + 15) >> 4) & 7) // aligned to 8
|
||||
#else
|
||||
if ((((m_vertex.buff[i].XYZ.X - ofx) + 15) >> 4) & 3) // aligned to 4
|
||||
if ((((m_vertex->buff[i].XYZ.X - ofx) + 15) >> 4) & 3) // aligned to 4
|
||||
#endif
|
||||
{
|
||||
gd.sel.notest = 0;
|
||||
|
||||
@@ -481,72 +481,26 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count, queue_family_properties.data());
|
||||
DevCon.WriteLn("%u vulkan queue families", queue_family_count);
|
||||
|
||||
std::vector<uint32_t> queue_family_users(queue_family_count, 0);
|
||||
|
||||
// Find graphics and present queues.
|
||||
m_graphics_queue_family_index = queue_family_count;
|
||||
m_present_queue_family_index = queue_family_count;
|
||||
u32 present_queue_index = 0;
|
||||
m_spin_queue_family_index = queue_family_count;
|
||||
u32 spin_queue_index = 0;
|
||||
|
||||
// Graphics Queue
|
||||
for (uint32_t i = 0; i < queue_family_count; i++)
|
||||
{
|
||||
if (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
VkBool32 graphics_supported = queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT;
|
||||
if (graphics_supported)
|
||||
{
|
||||
m_graphics_queue_family_index = i;
|
||||
queue_family_users[i]++;
|
||||
break;
|
||||
// Quit now, no need for a present queue.
|
||||
if (!surface)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spinwait Queue
|
||||
for (uint32_t i = 0; i < queue_family_count; i++)
|
||||
{
|
||||
if (queue_family_properties[i].queueCount == queue_family_users[i])
|
||||
continue;
|
||||
if (!(queue_family_properties[i].queueFlags & VK_QUEUE_COMPUTE_BIT))
|
||||
continue;
|
||||
if (queue_family_properties[i].timestampValidBits == 0)
|
||||
continue; // We need timing
|
||||
|
||||
if (!(queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
|
||||
if (surface)
|
||||
{
|
||||
m_spin_queue_family_index = i;
|
||||
break;
|
||||
}
|
||||
else if (m_spin_queue_family_index == queue_family_count)
|
||||
m_spin_queue_family_index = i;
|
||||
}
|
||||
|
||||
if (m_spin_queue_family_index != queue_family_count)
|
||||
{
|
||||
spin_queue_index = queue_family_users[m_spin_queue_family_index];
|
||||
queue_family_users[m_spin_queue_family_index]++;
|
||||
m_spin_queue_is_graphics_queue = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No spare queue? Try the graphics queue.
|
||||
if ((queue_family_properties[m_graphics_queue_family_index].queueFlags & VK_QUEUE_COMPUTE_BIT) &&
|
||||
(queue_family_properties[m_graphics_queue_family_index].timestampValidBits != 0))
|
||||
{
|
||||
m_spin_queue_family_index = m_graphics_queue_family_index;
|
||||
spin_queue_index = 0;
|
||||
m_spin_queue_is_graphics_queue = true;
|
||||
}
|
||||
else
|
||||
m_spin_queue_is_graphics_queue = false;
|
||||
}
|
||||
|
||||
// Present Queue
|
||||
if (surface)
|
||||
{
|
||||
for (uint32_t i = 0; i < queue_family_count; i++)
|
||||
{
|
||||
if (queue_family_properties[i].queueCount == queue_family_users[i])
|
||||
continue;
|
||||
|
||||
VkBool32 present_supported;
|
||||
VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(m_physical_device, i, surface, &present_supported);
|
||||
if (res != VK_SUCCESS)
|
||||
@@ -555,48 +509,35 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!present_supported)
|
||||
continue;
|
||||
|
||||
// Perfer aync compute queue
|
||||
if ((queue_family_properties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) &&
|
||||
!(queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
|
||||
{
|
||||
m_present_queue_family_index = i;
|
||||
break;
|
||||
}
|
||||
else if (m_present_queue_family_index == queue_family_count)
|
||||
m_present_queue_family_index = i;
|
||||
}
|
||||
|
||||
if (m_present_queue_family_index != queue_family_count)
|
||||
{
|
||||
present_queue_index = queue_family_users[m_present_queue_family_index];
|
||||
queue_family_users[m_present_queue_family_index]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No spare queue? Try the graphics queue.
|
||||
VkBool32 present_supported;
|
||||
VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(m_physical_device, m_graphics_queue_family_index, surface, &present_supported);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceSupportKHR failed: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (present_supported)
|
||||
{
|
||||
m_present_queue_family_index = m_graphics_queue_family_index;
|
||||
present_queue_index = 0;
|
||||
m_present_queue_family_index = i;
|
||||
}
|
||||
|
||||
// Prefer one queue family index that does both graphics and present.
|
||||
if (graphics_supported && present_supported)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Swap spin and present to simplify queue priorities logic.
|
||||
if (!m_spin_queue_is_graphics_queue && m_present_queue_family_index == m_spin_queue_family_index)
|
||||
std::swap(spin_queue_index, present_queue_index);
|
||||
|
||||
for (uint32_t i = 0; i < queue_family_count; i++)
|
||||
{
|
||||
// Pick a queue for spinning
|
||||
if (!(queue_family_properties[i].queueFlags & VK_QUEUE_COMPUTE_BIT))
|
||||
continue; // We need compute
|
||||
if (queue_family_properties[i].timestampValidBits == 0)
|
||||
continue; // We need timing
|
||||
const bool queue_is_used = i == m_graphics_queue_family_index || i == m_present_queue_family_index;
|
||||
if (queue_is_used && m_spin_queue_family_index != queue_family_count)
|
||||
continue; // Found a non-graphics queue to use
|
||||
spin_queue_index = 0;
|
||||
m_spin_queue_family_index = i;
|
||||
if (queue_is_used && queue_family_properties[i].queueCount > 1)
|
||||
spin_queue_index = 1;
|
||||
if (!(queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
|
||||
break; // Async compute queue, definitely pick this one
|
||||
}
|
||||
if (m_graphics_queue_family_index == queue_family_count)
|
||||
{
|
||||
Console.Error("VK: Failed to find an acceptable graphics queue.");
|
||||
@@ -614,16 +555,14 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
device_info.flags = 0;
|
||||
device_info.queueCreateInfoCount = 0;
|
||||
|
||||
// Low priority for the spin queue
|
||||
static constexpr float queue_priorities[] = {1.0f, 1.0f, 0.0f};
|
||||
|
||||
static constexpr float queue_priorities[] = {1.0f, 0.0f}; // Low priority for the spin queue
|
||||
std::array<VkDeviceQueueCreateInfo, 3> queue_infos;
|
||||
VkDeviceQueueCreateInfo& graphics_queue_info = queue_infos[device_info.queueCreateInfoCount++];
|
||||
graphics_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
graphics_queue_info.pNext = nullptr;
|
||||
graphics_queue_info.flags = 0;
|
||||
graphics_queue_info.queueFamilyIndex = m_graphics_queue_family_index;
|
||||
graphics_queue_info.queueCount = queue_family_users[m_graphics_queue_family_index];
|
||||
graphics_queue_info.queueCount = 1;
|
||||
graphics_queue_info.pQueuePriorities = queue_priorities;
|
||||
|
||||
if (surface != VK_NULL_HANDLE && m_graphics_queue_family_index != m_present_queue_family_index)
|
||||
@@ -633,19 +572,19 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
present_queue_info.pNext = nullptr;
|
||||
present_queue_info.flags = 0;
|
||||
present_queue_info.queueFamilyIndex = m_present_queue_family_index;
|
||||
present_queue_info.queueCount = queue_family_users[m_present_queue_family_index];
|
||||
present_queue_info.queueCount = 1;
|
||||
present_queue_info.pQueuePriorities = queue_priorities;
|
||||
}
|
||||
|
||||
if (m_spin_queue_family_index == m_graphics_queue_family_index)
|
||||
{
|
||||
if (spin_queue_index == 1)
|
||||
graphics_queue_info.pQueuePriorities = queue_priorities + 1;
|
||||
if (spin_queue_index != 0)
|
||||
graphics_queue_info.queueCount = 2;
|
||||
}
|
||||
else if (m_spin_queue_family_index == m_present_queue_family_index)
|
||||
{
|
||||
if (spin_queue_index == 1)
|
||||
queue_infos[1].pQueuePriorities = queue_priorities + 1;
|
||||
if (spin_queue_index != 0)
|
||||
queue_infos[1].queueCount = 2; // present queue
|
||||
}
|
||||
else if (m_spin_queue_family_index != queue_family_count)
|
||||
{
|
||||
@@ -655,7 +594,7 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
spin_queue_info.flags = 0;
|
||||
spin_queue_info.queueFamilyIndex = m_spin_queue_family_index;
|
||||
spin_queue_info.queueCount = 1;
|
||||
spin_queue_info.pQueuePriorities = queue_priorities + 2;
|
||||
spin_queue_info.pQueuePriorities = queue_priorities + 1;
|
||||
}
|
||||
|
||||
device_info.pQueueCreateInfos = queue_infos.data();
|
||||
@@ -744,11 +683,13 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
vkGetDeviceQueue(m_device, m_graphics_queue_family_index, 0, &m_graphics_queue);
|
||||
if (surface)
|
||||
{
|
||||
vkGetDeviceQueue(m_device, m_present_queue_family_index, present_queue_index, &m_present_queue);
|
||||
vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue);
|
||||
}
|
||||
m_spinning_supported = m_spin_queue_family_index != queue_family_count &&
|
||||
queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0 &&
|
||||
m_device_properties.limits.timestampPeriod > 0;
|
||||
m_spin_queue_is_graphics_queue =
|
||||
m_spin_queue_family_index == m_graphics_queue_family_index && spin_queue_index == 0;
|
||||
|
||||
m_gpu_timing_supported = (m_device_properties.limits.timestampComputeAndGraphics != 0 &&
|
||||
queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0 &&
|
||||
@@ -1354,7 +1295,7 @@ void GSDeviceVK::SubmitCommandBuffer(VKSwapChain* present_swap_chain)
|
||||
|
||||
present_swap_chain->ResetImageAcquireResult();
|
||||
|
||||
const VkResult res = vkQueuePresentKHR(m_present_queue, &present_info);
|
||||
res = vkQueuePresentKHR(m_present_queue, &present_info);
|
||||
if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR)
|
||||
{
|
||||
// VK_ERROR_OUT_OF_DATE_KHR is not fatal, just means we need to recreate our swap chain.
|
||||
|
||||
@@ -1923,7 +1923,6 @@ Pcsx2Config::Pcsx2Config()
|
||||
{
|
||||
bitset = 0;
|
||||
// Set defaults for fresh installs / reset settings
|
||||
McdFolderAutoManage = true;
|
||||
EnablePatches = true;
|
||||
EnableFastBoot = true;
|
||||
EnableRecordingTools = true;
|
||||
@@ -1979,7 +1978,6 @@ void Pcsx2Config::LoadSaveCore(SettingsWrapper& wrap)
|
||||
SettingsWrapBitBool(HostFs);
|
||||
|
||||
SettingsWrapBitBool(BackupSavestate);
|
||||
SettingsWrapBitBool(McdFolderAutoManage);
|
||||
|
||||
SettingsWrapBitBool(WarnAboutUnsafeSettings);
|
||||
|
||||
|
||||
@@ -611,7 +611,7 @@ void FileMcd_EmuOpen()
|
||||
|
||||
|
||||
Mcd::impl.Open();
|
||||
Mcd::implFolder.SetFiltering(EmuConfig.McdFolderAutoManage);
|
||||
Mcd::implFolder.SetFiltering(true);
|
||||
Mcd::implFolder.Open();
|
||||
}
|
||||
|
||||
@@ -823,7 +823,7 @@ int FileMcd_ReIndex(uint port, uint slot, const std::string& filter)
|
||||
// return Mcd::impl.ReIndex( combinedSlot, filter );
|
||||
// break;
|
||||
case MemoryCardType::Folder:
|
||||
if (!Mcd::implFolder.ReIndex(combinedSlot, EmuConfig.McdFolderAutoManage, filter))
|
||||
if (!Mcd::implFolder.ReIndex(combinedSlot, true, filter))
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
@@ -930,7 +930,7 @@ std::vector<AvailableMcdInfo> FileMcd_GetAvailableCards(bool include_in_use_card
|
||||
Pcsx2Config::McdOptions config;
|
||||
config.Enabled = true;
|
||||
config.Type = MemoryCardType::Folder;
|
||||
sourceFolderMemoryCard.Open(fd.FileName, config, (8 * 1024 * 1024) / FolderMemoryCard::ClusterSize, EmuConfig.McdFolderAutoManage, "");
|
||||
sourceFolderMemoryCard.Open(fd.FileName, config, (8 * 1024 * 1024) / FolderMemoryCard::ClusterSize, true, "");
|
||||
|
||||
mcds.push_back({std::move(basename), std::move(fd.FileName), fd.ModificationTime,
|
||||
MemoryCardType::Folder, MemoryCardFileType::Unknown, 0u, sourceFolderMemoryCard.IsFormatted()});
|
||||
|
||||
@@ -218,7 +218,7 @@ void Pad::SetDefaultHotkeyConfig(SettingsInterface& si)
|
||||
// PCSX2 Controller Settings - Hotkeys
|
||||
|
||||
// PCSX2 Controller Settings - Hotkeys - General
|
||||
si.SetStringValue("Hotkeys", "ToggleFullscreen", "Keyboard/LAlt & Keyboard/Return");
|
||||
si.SetStringValue("Hotkeys", "ToggleFullscreen", "Keyboard/Alt & Keyboard/Return");
|
||||
|
||||
// PCSX2 Controller Settings - Hotkeys - Graphics
|
||||
si.SetStringValue("Hotkeys", "CycleAspectRatio", "Keyboard/F6");
|
||||
@@ -228,24 +228,24 @@ void Pad::SetDefaultHotkeyConfig(SettingsInterface& si)
|
||||
// si.SetStringValue("Hotkeys", "DecreaseUpscaleMultiplier", "Keyboard"); TBD
|
||||
// si.SetStringValue("Hotkeys", "IncreaseUpscaleMultiplier", "Keyboard"); TBD
|
||||
// si.SetStringValue("Hotkeys", "ReloadTextureReplacements", "Keyboard"); TBD
|
||||
si.SetStringValue("Hotkeys", "GSDumpMultiFrame", "Keyboard/RCtrl & Keyboard/RShift & Keyboard/F8");
|
||||
si.SetStringValue("Hotkeys", "GSDumpMultiFrame", "Keyboard/Control & Keyboard/Shift & Keyboard/F8");
|
||||
si.SetStringValue("Hotkeys", "Screenshot", "Keyboard/F8");
|
||||
si.SetStringValue("Hotkeys", "GSDumpSingleFrame", "Keyboard/RShift & Keyboard/F8");
|
||||
si.SetStringValue("Hotkeys", "GSDumpSingleFrame", "Keyboard/Shift & Keyboard/F8");
|
||||
si.SetStringValue("Hotkeys", "ToggleSoftwareRendering", "Keyboard/F9");
|
||||
// si.SetStringValue("Hotkeys", "ToggleTextureDumping", "Keyboard"); TBD
|
||||
// si.SetStringValue("Hotkeys", "ToggleTextureReplacements", "Keyboard"); TBD
|
||||
si.SetStringValue("Hotkeys", "ZoomIn", "Keyboard/LCtrl & Keyboard/Plus");
|
||||
si.SetStringValue("Hotkeys", "ZoomOut", "Keyboard/LCtrl & Keyboard/Minus");
|
||||
// Missing hotkey for resetting zoom back to 100 with Keyboard/LCtrl & Keyboard/Asterisk
|
||||
si.SetStringValue("Hotkeys", "ZoomIn", "Keyboard/Control & Keyboard/Plus");
|
||||
si.SetStringValue("Hotkeys", "ZoomOut", "Keyboard/Control & Keyboard/Minus");
|
||||
// Missing hotkey for resetting zoom back to 100 with Keyboard/Control & Keyboard/Asterisk
|
||||
|
||||
// PCSX2 Controller Settings - Hotkeys - Input Recording
|
||||
si.SetStringValue("Hotkeys", "InputRecToggleMode", "Keyboard/LShift & Keyboard/R");
|
||||
si.SetStringValue("Hotkeys", "InputRecToggleMode", "Keyboard/Shift & Keyboard/R");
|
||||
|
||||
// PCSX2 Controller Settings - Hotkeys - Save States
|
||||
si.SetStringValue("Hotkeys", "LoadStateFromSlot", "Keyboard/F3");
|
||||
si.SetStringValue("Hotkeys", "SaveStateToSlot", "Keyboard/F1");
|
||||
si.SetStringValue("Hotkeys", "NextSaveStateSlot", "Keyboard/F2");
|
||||
si.SetStringValue("Hotkeys", "PreviousSaveStateSlot", "Keyboard/LShift & Keyboard/F2");
|
||||
si.SetStringValue("Hotkeys", "PreviousSaveStateSlot", "Keyboard/Shift & Keyboard/F2");
|
||||
|
||||
// PCSX2 Controller Settings - Hotkeys - System
|
||||
// si.SetStringValue("Hotkeys", "DecreaseSpeed", "Keyboard"); TBD
|
||||
@@ -256,7 +256,7 @@ void Pad::SetDefaultHotkeyConfig(SettingsInterface& si)
|
||||
si.SetStringValue("Hotkeys", "OpenPauseMenu", "Keyboard/Escape");
|
||||
si.SetStringValue("Hotkeys", "ToggleFrameLimit", "Keyboard/F4");
|
||||
si.SetStringValue("Hotkeys", "TogglePause", "Keyboard/Space");
|
||||
si.SetStringValue("Hotkeys", "ToggleSlowMotion", "Keyboard/LShift & Keyboard/Backtab");
|
||||
si.SetStringValue("Hotkeys", "ToggleSlowMotion", "Keyboard/Shift & Keyboard/Backtab");
|
||||
si.SetStringValue("Hotkeys", "ToggleTurbo", "Keyboard/Tab");
|
||||
si.SetStringValue("Hotkeys", "HoldTurbo", "Keyboard/Period");
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
/// Version number for GS and other shaders. Increment whenever any of the contents of the
|
||||
/// shaders change, to invalidate the cache.
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 78;
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 80;
|
||||
|
||||
@@ -2993,8 +2993,6 @@ void VMManager::CheckForMemoryCardConfigChanges(const Pcsx2Config& old_config)
|
||||
}
|
||||
}
|
||||
|
||||
changed |= (EmuConfig.McdFolderAutoManage != old_config.McdFolderAutoManage);
|
||||
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user