mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-08-18 20:03:11 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
224863fbd5 | ||
|
|
1d459d8fab | ||
|
|
33e0ac729e | ||
|
|
268ecf42c3 | ||
|
|
708281f00b | ||
|
|
56b68a50e9 | ||
|
|
e4048dc2dd | ||
|
|
5949c772d1 | ||
|
|
63998b64cc | ||
|
|
fbb3ea142a | ||
|
|
435f760b5d | ||
|
|
f47129bd72 | ||
|
|
aa42acfe22 | ||
|
|
ddfe6ac5c1 | ||
|
|
624dff1b96 | ||
|
|
8d498b564d | ||
|
|
26561261bc | ||
|
|
44728be719 | ||
|
|
678bb1218b | ||
|
|
c496e80eac | ||
|
|
269db188d0 | ||
|
|
f5afbfd4f5 | ||
|
|
ccd86a242c | ||
|
|
42a5cb7ad2 | ||
|
|
6977323d88 | ||
|
|
7b1d03d45a | ||
|
|
8a4f1ef51a | ||
|
|
9b50bb2e81 | ||
|
|
4f27d779a1 | ||
|
|
73c6353351 | ||
|
|
f571b66a43 | ||
|
|
901664ba44 | ||
|
|
02012b5491 | ||
|
|
4f57e40c91 | ||
|
|
832e536a9e | ||
|
|
c2316ca5bc | ||
|
|
3535edcfa1 | ||
|
|
a4932ed0f1 | ||
|
|
515d9040a1 | ||
|
|
fe3a743814 | ||
|
|
8e08cd772b | ||
|
|
206f80c5f4 | ||
|
|
c6ce380042 | ||
|
|
939d98d660 | ||
|
|
c9a3420f85 | ||
|
|
9a1a399bac | ||
|
|
c8aac1dca9 | ||
|
|
14c17916f5 | ||
|
|
7b0576d7cc | ||
|
|
ecb118d5af | ||
|
|
efbf187b35 | ||
|
|
2ea3feba90 | ||
|
|
f265257efb | ||
|
|
13cc0caed7 | ||
|
|
2068240e1a | ||
|
|
7f5901f022 | ||
|
|
a022de6225 | ||
|
|
f5570b7f40 | ||
|
|
7e1c48694a | ||
|
|
a546f61ea8 | ||
|
|
7ecac10eee | ||
|
|
ee2e10e86b | ||
|
|
7752f44a90 | ||
|
|
e01fc3eb47 | ||
|
|
910c8190e0 | ||
|
|
a62ccc0d69 | ||
|
|
4f47041108 | ||
|
|
16cfde0538 | ||
|
|
6a15d46461 | ||
|
|
4331ae1925 | ||
|
|
4d85d916b7 | ||
|
|
4f4b14dd4d | ||
|
|
444e650711 | ||
|
|
c65ccaa153 | ||
|
|
6b54db9b75 | ||
|
|
3bab470db6 | ||
|
|
adf01cb56a | ||
|
|
bbe3af7f61 | ||
|
|
3e7d32c807 | ||
|
|
76e25cb738 | ||
|
|
8f0dc34847 | ||
|
|
fc6ec2cc02 | ||
|
|
34b7b07ff8 | ||
|
|
6c33b73cdd | ||
|
|
1e86ba4120 | ||
|
|
89c79aa6c3 | ||
|
|
4ed748fa30 | ||
|
|
5569e94f41 | ||
|
|
892eec79ed | ||
|
|
b248b4a8af | ||
|
|
39fe467b64 | ||
|
|
1c301ec889 | ||
|
|
de5690ddcb | ||
|
|
f376c8f7ae | ||
|
|
2e199d47a8 | ||
|
|
96269db93e | ||
|
|
d35db63d73 | ||
|
|
9d003486c2 | ||
|
|
0c4b85980c | ||
|
|
5961db6b9b | ||
|
|
d0039c2920 | ||
|
|
5bdec2f532 | ||
|
|
fd758bb307 | ||
|
|
a11d09ebdf | ||
|
|
d294064da6 | ||
|
|
fd4a5acc40 | ||
|
|
05a7a61257 | ||
|
|
90a4a11d49 | ||
|
|
d9f914eb7c | ||
|
|
134242973b | ||
|
|
92900d8dc8 | ||
|
|
7a970e1d00 |
@@ -27,6 +27,11 @@
|
||||
'GUI/WX':
|
||||
- 'pcsx2/gui/*'
|
||||
- 'pcsx2/gui/**/*'
|
||||
- 'pcsx2/SPU2/wx/*'
|
||||
- 'pcsx2/SPU2/wx/**/*'
|
||||
- 'pcsx2/PAD/Linux/wx_dialog/*'
|
||||
- 'pcsx2/PAD/Linux/wx_dialog/**/*'
|
||||
- 'pcsx2/GS/Window/GSwxDialog.h'
|
||||
'GUI/Qt':
|
||||
- 'pcsx2-qt/*'
|
||||
- 'pcsx2-qt/**/*'
|
||||
|
||||
@@ -44,12 +44,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
platform: x86
|
||||
compiler: gcc
|
||||
cmakeflags: -DLTO_PCSX2_CORE=ON
|
||||
appimage: true
|
||||
experimental: false
|
||||
- os: ubuntu-18.04
|
||||
platform: x64
|
||||
compiler: gcc
|
||||
@@ -57,7 +51,7 @@ jobs:
|
||||
appimage: true
|
||||
experimental: false
|
||||
- os: ubuntu-18.04
|
||||
platform: x86
|
||||
platform: x64
|
||||
compiler: clang
|
||||
# Need to disable PCH until cmake 3.17
|
||||
# (PCH conflicts with ccache, fixed by https://gitlab.kitware.com/cmake/cmake/-/merge_requests/4400)
|
||||
@@ -66,21 +60,21 @@ jobs:
|
||||
appimage: false
|
||||
experimental: false
|
||||
- os: ubuntu-18.04
|
||||
platform: x86
|
||||
platform: x64
|
||||
compiler: gcc
|
||||
cmakeflags: -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON
|
||||
detail: " nopch"
|
||||
appimage: false
|
||||
experimental: false
|
||||
- os: ubuntu-18.04
|
||||
platform: x86
|
||||
platform: x64
|
||||
compiler: gcc
|
||||
cmakeflags: -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -DARCH_FLAG=-march=haswell
|
||||
detail: " avx2 nopch"
|
||||
appimage: false
|
||||
experimental: false
|
||||
|
||||
name: ${{ matrix.platform }} | ${{ matrix.compiler }}${{ matrix.detail }}
|
||||
name: ${{ matrix.compiler }}${{ matrix.detail }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
# Set some sort of timeout in the event of run-away builds. We are limited on concurrent jobs so, get rid of them.
|
||||
|
||||
@@ -70,7 +70,6 @@ jobs:
|
||||
platform: [x64]
|
||||
experimental: [false]
|
||||
|
||||
name: ${{ matrix.platform }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
# Set some sort of timeout in the event of run-away builds. We are limited on concurrent jobs so, get rid of them.
|
||||
|
||||
@@ -44,7 +44,8 @@ const embed = new MessageEmbed()
|
||||
{ name: 'Version', value: releaseInfo.tag_name, inline: true },
|
||||
{ name: 'Release Link', value: `[Github Release](${releaseInfo.html_url})`, inline: true },
|
||||
{ name: 'Installation Steps', value: '[See Here](https://github.com/PCSX2/pcsx2/wiki/Nightly-Build-Usage-Guide)', inline: true },
|
||||
{ name: 'Included Changes', value: releaseInfo.body, inline: false }
|
||||
{ name: 'Included Changes', value: releaseInfo.body, inline: false },
|
||||
{ name: 'Previous Builds', value: "[See Here](https://pcsx2.github.io/downloads.html#nightly-anchor)", inline: false }
|
||||
);
|
||||
|
||||
if (windowsAssetLinks != "") {
|
||||
|
||||
@@ -111,11 +111,8 @@ const { data: releaseAssetsPost } = await octokit.rest.repos.listReleaseAssets({
|
||||
|
||||
// Expected Assets, if we have all of them, we will publish it
|
||||
let expectedAssets = {
|
||||
"windows-32bit-sse4": false,
|
||||
"windows-32bit-avx2": false,
|
||||
"windows-64bit-sse4": false,
|
||||
"windows-64bit-avx2": false,
|
||||
"linux-appimage-32bit": false,
|
||||
"linux-appimage-64bit": false
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ allowed_game_options = [
|
||||
"roundModes",
|
||||
"clampModes",
|
||||
"gameFixes",
|
||||
"gsHWFixes",
|
||||
"speedHacks",
|
||||
"memcardFilters",
|
||||
"patches",
|
||||
@@ -19,24 +20,54 @@ allowed_game_options = [
|
||||
allowed_round_modes = ["eeRoundMode", "vuRoundMode"]
|
||||
allowed_clamp_modes = ["eeClampMode", "vuClampMode"]
|
||||
allowed_game_fixes = [
|
||||
"VuAddSubHack",
|
||||
"FpuCompareHack",
|
||||
"FpuMulHack",
|
||||
"FpuNegDivHack",
|
||||
"XGKickHack",
|
||||
"EETimingHack",
|
||||
"GoemonTlbHack",
|
||||
"SoftwareRendererFMVHack",
|
||||
"SkipMPEGHack",
|
||||
"OPHFlagHack",
|
||||
"EETimingHack",
|
||||
"DMABusyHack",
|
||||
"GIFFIFOHack",
|
||||
"VIFFIFOHack",
|
||||
"VIF1StallHack",
|
||||
"GIFFIFOHack",
|
||||
"GoemonTlbHack",
|
||||
"VUSyncHack",
|
||||
"VuAddSubHack",
|
||||
"IbitHack",
|
||||
"VUSyncHack",
|
||||
"VUOverflowHack",
|
||||
"XGKickHack",
|
||||
]
|
||||
allowed_speed_hacks = ["mvuFlagSpeedHack", "InstantVU1SpeedHack"]
|
||||
allowed_gs_hw_fixes = [
|
||||
"autoFlush",
|
||||
"conservativeFramebuffer",
|
||||
"cpuFramebufferConversion",
|
||||
"disableDepthSupport",
|
||||
"wrapGSMem",
|
||||
"preloadFrameData",
|
||||
"disablePartialInvalidation",
|
||||
"textureInsideRT",
|
||||
"alignSprite",
|
||||
"mergeSprite",
|
||||
"wildArmsHack",
|
||||
"pointListPalette",
|
||||
"mipmap",
|
||||
"trilinearFiltering",
|
||||
"skipDrawStart",
|
||||
"skipDrawEnd",
|
||||
"halfBottomOverride",
|
||||
"halfPixelOffset",
|
||||
"roundSprite",
|
||||
"texturePreloading",
|
||||
]
|
||||
gs_hw_fix_ranges = {
|
||||
"mipmap": (0, 2),
|
||||
"trilinearFiltering": (0, 2),
|
||||
"skipDrawStart": (0, 100000),
|
||||
"skipDrawEnd": (0, 100000),
|
||||
"halfPixelOffset": (0, 3),
|
||||
"roundSprite": (0, 2),
|
||||
}
|
||||
allowed_speed_hacks = ["mvuFlagSpeedHack", "InstantVU1SpeedHack", "MTVUSpeedHack"]
|
||||
# Patches are allowed to have a 'default' key or a crc-32 key, followed by
|
||||
allowed_patch_options = ["author", "content"]
|
||||
|
||||
@@ -94,6 +125,29 @@ def validate_game_fixes(serial, key, value):
|
||||
validate_valid_options(serial, key, gamefix, allowed_game_fixes)
|
||||
|
||||
|
||||
def validate_gs_hw_fix_value(serial, key, value):
|
||||
low, high = 0, 1
|
||||
if key in gs_hw_fix_ranges:
|
||||
low, high = gs_hw_fix_ranges[key]
|
||||
validate_int_option(serial, key, value, low, high)
|
||||
|
||||
|
||||
def validate_gs_hw_fixes(serial, key, value):
|
||||
if not isinstance(value, dict):
|
||||
issue_list.append("[{}]: 'gsHWFixes' must be a valid object".format(serial))
|
||||
return
|
||||
for fix, fix_value in value.items():
|
||||
validate_valid_options(serial, key, fix, allowed_gs_hw_fixes)
|
||||
validate_gs_hw_fix_value(serial, fix, fix_value)
|
||||
|
||||
# skipdraw range must have end >= start
|
||||
skip_draw_start = value["skipDrawStart"] if "skipDrawStart" in value else 0
|
||||
skip_draw_end = value["skipDrawEnd"] if "skipDrawEnd" in value else 0
|
||||
if isinstance(skip_draw_start, int) and isinstance(skip_draw_end, int) and skip_draw_end < skip_draw_start:
|
||||
issue_list.append("[{}]: skipDrawStart({}) must be greater or equal to skipDrawEnd({})".format(
|
||||
serial, skip_draw_start, skip_draw_end))
|
||||
|
||||
|
||||
def validate_speed_hacks(serial, key, value):
|
||||
if not isinstance(value, dict):
|
||||
issue_list.append("[{}]: 'speedHacks' must be a valid object".format(serial))
|
||||
@@ -145,6 +199,7 @@ option_validation_handlers = {
|
||||
)
|
||||
),
|
||||
"gameFixes": (lambda serial, key, value: validate_game_fixes(serial, key, value)),
|
||||
"gsHWFixes": (lambda serial, key, value: validate_gs_hw_fixes(serial, key, value)),
|
||||
"speedHacks": (lambda serial, key, value: validate_speed_hacks(serial, key, value)),
|
||||
"memcardFilters": (
|
||||
lambda serial, key, value: validate_list_of_strings(serial, key, value)
|
||||
|
||||
@@ -41,14 +41,11 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-2019]
|
||||
platform: [Win32, x64]
|
||||
platform: [x64]
|
||||
configuration: [Release, Release AVX2, CMake, Qt]
|
||||
experimental: [false]
|
||||
exclude:
|
||||
- platform: win32
|
||||
configuration: Qt
|
||||
|
||||
name: ${{ matrix.platform }} | ${{ matrix.configuration }}
|
||||
name: ${{ matrix.configuration }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
# Set some sort of timeout in the event of run-away builds. We are limited on concurrent jobs so, get rid of them.
|
||||
@@ -70,18 +67,18 @@ jobs:
|
||||
run: git submodule update --init --recursive -j $env:NUMBER_OF_PROCESSORS
|
||||
|
||||
- name: Setup Buildcache
|
||||
if: matrix.configuration == 'CMake' # TODO: buildcache on VS
|
||||
uses: mikehardy/buildcache-action@v1.2.2
|
||||
with:
|
||||
cache_key: ${{ matrix.os }} ${{ matrix.platform }} ${{ matrix.configuration }}
|
||||
if: matrix.configuration == 'CMake' # TODO: buildcache on VS
|
||||
|
||||
- name: Verify VS Project Files
|
||||
run: .github\workflows\scripts\windows\validate-vs-filters.ps1
|
||||
if: matrix.configuration != 'CMake'
|
||||
run: .github\workflows\scripts\windows\validate-vs-filters.ps1
|
||||
|
||||
- name: Setup msbuild
|
||||
uses: microsoft/setup-msbuild@v1
|
||||
if: matrix.configuration != 'CMake'
|
||||
uses: microsoft/setup-msbuild@v1
|
||||
|
||||
- name: Download Qt build files
|
||||
if: matrix.configuration == 'Qt'
|
||||
@@ -93,6 +90,7 @@ jobs:
|
||||
del qt-6.2.2-x64.7z
|
||||
|
||||
- name: Generate CMake
|
||||
if: matrix.configuration == 'CMake'
|
||||
id: cmake
|
||||
shell: cmd
|
||||
run: |
|
||||
@@ -102,7 +100,6 @@ jobs:
|
||||
echo ::set-output name=buildtype::%type%
|
||||
echo ::set-output name=vcvars::%vcvars%
|
||||
cmake . -B build -DCMAKE_BUILD_TYPE=%type% -DLTO_PCSX2_CORE=ON -G Ninja -DCMAKE_C_COMPILER_LAUNCHER=..\buildcache\bin\buildcache.exe -DCMAKE_CXX_COMPILER_LAUNCHER=..\buildcache\bin\buildcache.exe -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON
|
||||
if: matrix.configuration == 'CMake'
|
||||
|
||||
- name: Build PCSX2
|
||||
shell: cmd
|
||||
@@ -123,11 +120,11 @@ jobs:
|
||||
)
|
||||
|
||||
- name: Run Tests
|
||||
if: matrix.configuration == 'CMake'
|
||||
shell: cmd
|
||||
run: |
|
||||
call "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\${{ steps.cmake.outputs.vcvars }}"
|
||||
cmake --build build --config ${{ steps.cmake.outputs.buildtype }} --target unittests
|
||||
if: matrix.configuration == 'CMake'
|
||||
|
||||
- name: Prepare Artifact Metadata
|
||||
id: artifact-metadata
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/rapidyaml/rapidyaml updated: cf902dc49c...213b201d26
Vendored
+10
-15
@@ -52,6 +52,7 @@
|
||||
<ClInclude Include="rapidyaml\src\ryml_std.hpp" />
|
||||
<ClInclude Include="rapidyaml\src\c4\yml\detail\checks.hpp" />
|
||||
<ClInclude Include="rapidyaml\src\c4\yml\detail\parser_dbg.hpp" />
|
||||
<ClInclude Include="rapidyaml\src\c4\yml\detail\print.hpp" />
|
||||
<ClInclude Include="rapidyaml\src\c4\yml\detail\stack.hpp" />
|
||||
<ClInclude Include="rapidyaml\src\c4\yml\common.hpp" />
|
||||
<ClCompile Include="rapidyaml\src\c4\yml\common.cpp" />
|
||||
@@ -72,8 +73,7 @@
|
||||
<ClCompile Include="rapidyaml\src\c4\yml\tree.cpp" />
|
||||
<ClInclude Include="rapidyaml\src\c4\yml\writer.hpp" />
|
||||
<ClInclude Include="rapidyaml\src\c4\yml\yml.hpp" />
|
||||
<Natvis Include="rapidyaml\src\ryml.natvis">
|
||||
</Natvis>
|
||||
<Natvis Include="rapidyaml\src\ryml.natvis"></Natvis>
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\allocator.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\base64.hpp" />
|
||||
<ClCompile Include="rapidyaml\ext\c4core\src\c4\base64.cpp" />
|
||||
@@ -89,6 +89,7 @@
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\config.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\cpu.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ctor_dtor.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\dump.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\enum.hpp" />
|
||||
<ClCompile Include="rapidyaml\ext\c4core\src\c4\error.cpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\error.hpp" />
|
||||
@@ -107,35 +108,29 @@
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\restrict.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\span.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\std.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\std_fwd.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\string.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\string_fwd.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\tuple.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\vector.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\vector_fwd.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\substr.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\substr_fwd.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\szconv.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\time.hpp" />
|
||||
<ClCompile Include="rapidyaml\ext\c4core\src\c4\time.cpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\type_name.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\types.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\unrestrict.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\utf.hpp" />
|
||||
<ClCompile Include="rapidyaml\ext\c4core\src\c4\utf.cpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\windows.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\windows_pop.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\windows_push.hpp" />
|
||||
<Natvis Include="rapidyaml\ext\c4core\src\c4\c4core.natvis">
|
||||
</Natvis>
|
||||
<Natvis Include="rapidyaml\ext\c4core\src\c4\c4core.natvis"></Natvis>
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\debugbreak\debugbreak.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\rng\rng.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\sg14\inplace_function.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float.hpp" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\ascii_number.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\bigint.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\decimal_to_binary.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\digit_comparison.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\fast_float.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\fast_table.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\float_common.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\parse_number.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\simple_decimal_conversion.h" />
|
||||
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float_all.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
+1
-294
@@ -54,6 +54,7 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glad", "3rdparty\glad\glad.vcxproj", "{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ryml", "3rdparty\rapidyaml\ryml.vcxproj", "{DE9653B6-17DD-356A-9EE0-28A731772587}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cubeb", "3rdparty\cubeb\cubeb.vcxproj", "{BF74C473-DC04-44B3-92E8-4145F4E77342}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleini", "3rdparty\simpleini\simpleini.vcxproj", "{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}"
|
||||
@@ -64,594 +65,300 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang", "3rdparty\glslang
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug AVX2|Win32 = Debug AVX2|Win32
|
||||
Debug AVX2|x64 = Debug AVX2|x64
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Devel AVX2|Win32 = Devel AVX2|Win32
|
||||
Devel AVX2|x64 = Devel AVX2|x64
|
||||
Devel|Win32 = Devel|Win32
|
||||
Devel|x64 = Devel|x64
|
||||
Release AVX2|Win32 = Release AVX2|Win32
|
||||
Release AVX2|x64 = Release AVX2|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug AVX2|Win32.ActiveCfg = Debug AVX2|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug AVX2|Win32.Build.0 = Debug AVX2|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug AVX2|x64.ActiveCfg = Debug AVX2|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug AVX2|x64.Build.0 = Debug AVX2|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Debug|x64.Build.0 = Debug|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Devel AVX2|Win32.ActiveCfg = Devel AVX2|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Devel AVX2|Win32.Build.0 = Devel AVX2|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Devel AVX2|x64.ActiveCfg = Devel AVX2|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Devel AVX2|x64.Build.0 = Devel AVX2|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Devel|x64.Build.0 = Devel|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release AVX2|Win32.ActiveCfg = Release AVX2|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release AVX2|Win32.Build.0 = Release AVX2|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release AVX2|x64.ActiveCfg = Release AVX2|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release AVX2|x64.Build.0 = Release AVX2|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|Win32.Build.0 = Release|Win32
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|x64.ActiveCfg = Release|x64
|
||||
{1CEFD830-2B76-4596-A4EE-BCD7280A60BD}.Release|x64.Build.0 = Release|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug|x64.Build.0 = Debug|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Devel|x64.Build.0 = Devel|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release|Win32.Build.0 = Release|Win32
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release|x64.ActiveCfg = Release|x64
|
||||
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Release|x64.Build.0 = Release|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Debug|x64.Build.0 = Debug|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Devel|x64.Build.0 = Devel|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release|Win32.Build.0 = Release|Win32
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release|x64.ActiveCfg = Release|x64
|
||||
{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release|x64.Build.0 = Release|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug|x64.Build.0 = Debug|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel|x64.Build.0 = Devel|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release|Win32.Build.0 = Release|Win32
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release|x64.ActiveCfg = Release|x64
|
||||
{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release|x64.Build.0 = Release|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Debug|x64.Build.0 = Debug|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Devel|x64.Build.0 = Devel|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release|Win32.Build.0 = Release|Win32
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release|x64.ActiveCfg = Release|x64
|
||||
{BC236261-77E8-4567-8D09-45CD02965EB6}.Release|x64.Build.0 = Release|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.Build.0 = Debug|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel|x64.Build.0 = Devel|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|Win32.Build.0 = Release|Win32
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.ActiveCfg = Release|x64
|
||||
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.Build.0 = Release|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.Build.0 = Debug|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel|x64.Build.0 = Devel|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|Win32.Build.0 = Release|Win32
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.ActiveCfg = Release|x64
|
||||
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.Build.0 = Release|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|x64.Build.0 = Debug|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Devel|x64.Build.0 = Devel|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release|Win32.Build.0 = Release|Win32
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release|x64.ActiveCfg = Release|x64
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release|x64.Build.0 = Release|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|x64.Build.0 = Debug|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Devel|x64.Build.0 = Devel|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release|Win32.Build.0 = Release|Win32
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release|x64.ActiveCfg = Release|x64
|
||||
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release|x64.Build.0 = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Devel|x64.Build.0 = Devel|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|Win32.Build.0 = Release|Win32
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug|x64.Build.0 = Debug|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel|x64.Build.0 = Devel|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release|Win32.Build.0 = Release|Win32
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release|x64.ActiveCfg = Release|x64
|
||||
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release|x64.Build.0 = Release|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug|x64.Build.0 = Debug|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Devel|x64.Build.0 = Devel|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release|Win32.Build.0 = Release|Win32
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release|x64.ActiveCfg = Release|x64
|
||||
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Release|x64.Build.0 = Release|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|x64.Build.0 = Debug|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Devel|x64.Build.0 = Devel|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|Win32.Build.0 = Release|Win32
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.ActiveCfg = Release|x64
|
||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.Build.0 = Release|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Debug|x64.Build.0 = Debug|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Devel|x64.Build.0 = Devel|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release|Win32.Build.0 = Release|Win32
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release|x64.ActiveCfg = Release|x64
|
||||
{449AD25E-424A-4714-BABC-68706CDCC33B}.Release|x64.Build.0 = Release|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug|x64.Build.0 = Debug|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel|x64.Build.0 = Devel|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|Win32.Build.0 = Release|Win32
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|x64.ActiveCfg = Release|x64
|
||||
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|x64.Build.0 = Release|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug|x64.Build.0 = Debug|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Devel|x64.Build.0 = Devel|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release|Win32.Build.0 = Release|Win32
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release|x64.ActiveCfg = Release|x64
|
||||
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Release|x64.Build.0 = Release|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Debug|x64.Build.0 = Debug|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Devel|x64.Build.0 = Devel|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release|Win32.Build.0 = Release|Win32
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release|x64.ActiveCfg = Release|x64
|
||||
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}.Release|x64.Build.0 = Release|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Debug|x64.Build.0 = Debug|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Devel|x64.Build.0 = Devel|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Release|Win32.Build.0 = Release|Win32
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Release|x64.ActiveCfg = Release|x64
|
||||
{4639972E-424E-4E13-8B07-CA403C481346}.Release|x64.Build.0 = Release|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Debug|x64.Build.0 = Debug|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Devel|x64.Build.0 = Devel|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|Win32.Build.0 = Release|Win32
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|x64.ActiveCfg = Release|x64
|
||||
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|x64.Build.0 = Release|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|x64.Build.0 = Debug|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|x64.Build.0 = Devel|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|Win32.Build.0 = Release|Win32
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|x64.ActiveCfg = Release|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|x64.Build.0 = Release|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|x64.Build.0 = Debug|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|x64.Build.0 = Devel|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|Win32.Build.0 = Release|Win32
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|x64.ActiveCfg = Release|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|x64.Build.0 = Release|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|x64.Build.0 = Debug|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|x64.Build.0 = Devel|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|Win32.Build.0 = Release|Win32
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|x64.ActiveCfg = Release|x64
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|x64.Build.0 = Release|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Debug|x64.Build.0 = Debug|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Devel|x64.Build.0 = Devel|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release|Win32.Build.0 = Release|Win32
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release|x64.ActiveCfg = Release|x64
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release|x64.Build.0 = Release|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug AVX2|Win32.Build.0 = Debug|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Debug|x64.Build.0 = Debug|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel AVX2|Win32.Build.0 = Devel|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel|Win32.ActiveCfg = Devel|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel|Win32.Build.0 = Devel|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Devel|x64.Build.0 = Devel|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release AVX2|Win32.ActiveCfg = Release|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release AVX2|Win32.Build.0 = Release|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release|Win32.Build.0 = Release|Win32
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release|x64.ActiveCfg = Release|x64
|
||||
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
|
||||
Binary file not shown.
+2509
-68
File diff suppressed because it is too large
Load Diff
@@ -402,7 +402,7 @@
|
||||
03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000007e0500001920000000000000,Nintendo Switch N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows,
|
||||
030000007e0500001720000000000000,Nintendo Switch Online Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,misc1:b13,platform:Windows,
|
||||
030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows,
|
||||
03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows,
|
||||
03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,platform:Windows,
|
||||
@@ -1112,6 +1112,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
030000005e040000ea02000008040000,Microsoft Xbox One S,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
|
||||
030000005e0400008902000021010000,Microsoft Xbox pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
|
||||
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
|
||||
050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
|
||||
@@ -140,44 +140,13 @@ endif()
|
||||
# Architecture bitness detection
|
||||
include(TargetArch)
|
||||
target_architecture(PCSX2_TARGET_ARCHITECTURES)
|
||||
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64" OR ${PCSX2_TARGET_ARCHITECTURES} MATCHES "i386")
|
||||
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
message(STATUS "Compiling a ${PCSX2_TARGET_ARCHITECTURES} build on a ${CMAKE_HOST_SYSTEM_PROCESSOR} host.")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported architecture: ${PCSX2_TARGET_ARCHITECTURES}")
|
||||
endif()
|
||||
|
||||
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "i386")
|
||||
# * -fPIC option was removed for multiple reasons.
|
||||
# - Code only supports the x86 architecture.
|
||||
# - code uses the ebx register so it's not compliant with PIC.
|
||||
# - Impacts the performance too much.
|
||||
# - Only plugins. No package will link to them.
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE OFF)
|
||||
|
||||
if(NOT DEFINED ARCH_FLAG)
|
||||
if (MSVC)
|
||||
set(ARCH_FLAG /arch:SSE2)
|
||||
else()
|
||||
if (DISABLE_ADVANCE_SIMD)
|
||||
if (USE_ICC)
|
||||
set(ARCH_FLAG "-msse2 -msse4.1")
|
||||
else()
|
||||
set(ARCH_FLAG "-msse -msse2 -msse4.1 -mfxsr -march=i686")
|
||||
endif()
|
||||
else()
|
||||
# AVX requires some fix of the ABI (mangling) (default 2)
|
||||
# Note: V6 requires GCC 4.7
|
||||
#set(ARCH_FLAG "-march=native -fabi-version=6")
|
||||
set(ARCH_FLAG "-mfxsr -march=native")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND PCSX2_DEFS _ARCH_32=1 _M_X86=1 _M_X86_32=1)
|
||||
set(_ARCH_32 1)
|
||||
set(_M_X86 1)
|
||||
set(_M_X86_32 1)
|
||||
elseif(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
# x86_64 requires -fPIC
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ target_sources(common PRIVATE
|
||||
emitter/LnxCpuDetect.cpp
|
||||
emitter/WinCpuDetect.cpp
|
||||
emitter/x86emitter.cpp
|
||||
x86/MemcpyFast.cpp
|
||||
Darwin/DarwinThreads.cpp
|
||||
Darwin/DarwinMisc.cpp
|
||||
Darwin/DarwinSemaphore.cpp
|
||||
|
||||
@@ -504,7 +504,7 @@ std::optional<std::vector<u8>> FileSystem::ReadBinaryFile(const char* filename)
|
||||
std::optional<std::vector<u8>> FileSystem::ReadBinaryFile(std::FILE* fp)
|
||||
{
|
||||
std::fseek(fp, 0, SEEK_END);
|
||||
long size = std::ftell(fp);
|
||||
const long size = std::ftell(fp);
|
||||
std::fseek(fp, 0, SEEK_SET);
|
||||
if (size < 0)
|
||||
return std::nullopt;
|
||||
@@ -528,13 +528,14 @@ std::optional<std::string> FileSystem::ReadFileToString(const char* filename)
|
||||
std::optional<std::string> FileSystem::ReadFileToString(std::FILE* fp)
|
||||
{
|
||||
std::fseek(fp, 0, SEEK_END);
|
||||
long size = std::ftell(fp);
|
||||
const long size = std::ftell(fp);
|
||||
std::fseek(fp, 0, SEEK_SET);
|
||||
if (size < 0)
|
||||
return std::nullopt;
|
||||
|
||||
std::string res;
|
||||
res.resize(static_cast<size_t>(size));
|
||||
// NOTE - assumes mode 'rb', for example, this will fail over missing Windows carriage return bytes
|
||||
if (size > 0 && std::fread(res.data(), 1u, static_cast<size_t>(size), fp) != static_cast<size_t>(size))
|
||||
return std::nullopt;
|
||||
|
||||
@@ -553,7 +554,7 @@ bool FileSystem::WriteBinaryFile(const char* filename, const void* data, size_t
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileSystem::WriteFileToString(const char* filename, const std::string_view& sv)
|
||||
bool FileSystem::WriteStringToFile(const char* filename, const std::string_view& sv)
|
||||
{
|
||||
ManagedCFilePtr fp = OpenManagedCFile(filename, "wb");
|
||||
if (!fp)
|
||||
@@ -1269,7 +1270,7 @@ bool FileSystem::FindFiles(const char* Path, const char* Pattern, u32 Flags, Fin
|
||||
|
||||
bool FileSystem::StatFile(const char* path, struct stat* st)
|
||||
{
|
||||
return stat(path, st);
|
||||
return stat(path, st) == 0;
|
||||
}
|
||||
|
||||
bool FileSystem::StatFile(std::FILE* fp, struct stat* st)
|
||||
@@ -1278,7 +1279,7 @@ bool FileSystem::StatFile(std::FILE* fp, struct stat* st)
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
return fstat(fd, st);
|
||||
return fstat(fd, st) == 0;
|
||||
}
|
||||
|
||||
bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* sd)
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@ namespace FileSystem
|
||||
std::optional<std::string> ReadFileToString(const char* filename);
|
||||
std::optional<std::string> ReadFileToString(std::FILE* fp);
|
||||
bool WriteBinaryFile(const char* filename, const void* data, size_t data_length);
|
||||
bool WriteFileToString(const char* filename, const std::string_view& sv);
|
||||
bool WriteStringToFile(const char* filename, const std::string_view& sv);
|
||||
|
||||
/// creates a directory in the local filesystem
|
||||
/// if the directory already exists, the return value will be true.
|
||||
|
||||
@@ -19,14 +19,6 @@
|
||||
#include "common/Pcsx2Types.h"
|
||||
#include "common/Pcsx2Defs.h"
|
||||
|
||||
// For 32-bit MSVC compiles, memcmp performs much worse than memcmp_mmx and
|
||||
// other implementations. So for this combination only, prefer memcmp_mmx
|
||||
#if defined(_MSC_VER) && !defined(_M_X86_64)
|
||||
extern u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize);
|
||||
#else
|
||||
#define memcmp_mmx memcmp
|
||||
#endif
|
||||
|
||||
// This method can clear any object-like entity -- which is anything that is not a pointer.
|
||||
// Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically
|
||||
// for you!
|
||||
|
||||
@@ -153,6 +153,17 @@ namespace StringUtil
|
||||
return (str.length() >= suffix_length && str.compare(str.length() - suffix_length, suffix_length, suffix) == 0);
|
||||
}
|
||||
|
||||
/// StartsWith/EndsWith variants which aren't case sensitive.
|
||||
static inline bool StartsWithNoCase(const std::string_view& str, const char* prefix)
|
||||
{
|
||||
return (Strncasecmp(str.data(), prefix, std::strlen(prefix)) == 0);
|
||||
}
|
||||
static inline bool EndsWithNoCase(const std::string_view& str, const char* suffix)
|
||||
{
|
||||
const std::size_t suffix_length = std::strlen(suffix);
|
||||
return (str.length() >= suffix_length && Strncasecmp(str.data() + (str.length() - suffix_length), suffix, suffix_length) == 0);
|
||||
}
|
||||
|
||||
/// Strip whitespace from the start/end of the string.
|
||||
std::string_view StripWhitespace(const std::string_view& str);
|
||||
|
||||
|
||||
@@ -621,6 +621,9 @@ namespace Vulkan
|
||||
vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue);
|
||||
}
|
||||
|
||||
m_gpu_timing_supported = (queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0);
|
||||
DevCon.WriteLn("GPU timing is %s", m_gpu_timing_supported ? "supported" : "not supported");
|
||||
|
||||
ProcessDeviceExtensions();
|
||||
return true;
|
||||
}
|
||||
@@ -823,11 +826,30 @@ namespace Vulkan
|
||||
return false;
|
||||
}
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_global_descriptor_pool, "Global Descriptor Pool");
|
||||
|
||||
if (m_gpu_timing_supported)
|
||||
{
|
||||
const VkQueryPoolCreateInfo query_create_info = {VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, nullptr,
|
||||
0, VK_QUERY_TYPE_TIMESTAMP, NUM_COMMAND_BUFFERS * 2, 0};
|
||||
res = vkCreateQueryPool(m_device, &query_create_info, nullptr, &m_timestamp_query_pool);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateQueryPool failed: ");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Context::DestroyGlobalDescriptorPool()
|
||||
{
|
||||
if (m_timestamp_query_pool != VK_NULL_HANDLE)
|
||||
{
|
||||
vkDestroyQueryPool(m_device, m_timestamp_query_pool, nullptr);
|
||||
m_timestamp_query_pool = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (m_global_descriptor_pool != VK_NULL_HANDLE)
|
||||
{
|
||||
vkDestroyDescriptorPool(m_device, m_global_descriptor_pool, nullptr);
|
||||
@@ -920,6 +942,18 @@ namespace Vulkan
|
||||
vkDeviceWaitIdle(m_device);
|
||||
}
|
||||
|
||||
float Context::GetAndResetAccumulatedGPUTime()
|
||||
{
|
||||
const float time = m_accumulated_gpu_time;
|
||||
m_accumulated_gpu_time = 0.0f;
|
||||
return time;
|
||||
}
|
||||
|
||||
void Context::SetEnableGPUTiming(bool enabled)
|
||||
{
|
||||
m_gpu_timing_enabled = enabled && m_gpu_timing_supported;
|
||||
}
|
||||
|
||||
void Context::WaitForCommandBufferCompletion(u32 index)
|
||||
{
|
||||
// Wait for this command buffer to be completed.
|
||||
@@ -968,6 +1002,11 @@ namespace Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
{
|
||||
vkCmdWriteTimestamp(m_current_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool, m_current_frame * 2 + 1);
|
||||
}
|
||||
|
||||
res = vkEndCommandBuffer(resources.command_buffers[1]);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
@@ -1145,6 +1184,29 @@ namespace Vulkan
|
||||
|
||||
// using the lower 32 bits of the fence index should be sufficient here, I hope...
|
||||
vmaSetCurrentFrameIndex(m_allocator, static_cast<u32>(m_next_fence_counter));
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
{
|
||||
std::array<u64, 2> timestamps;
|
||||
res = vkGetQueryPoolResults(m_device, m_timestamp_query_pool, index * 2, static_cast<u32>(timestamps.size()),
|
||||
sizeof(u64) * timestamps.size(), timestamps.data(), sizeof(u64), VK_QUERY_RESULT_64_BIT);
|
||||
if (res == VK_SUCCESS)
|
||||
{
|
||||
// if we didn't write the timestamp at the start of the cmdbuffer (just enabled timing), the first TS will be zero
|
||||
if (timestamps[0] > 0)
|
||||
{
|
||||
const u64 ns_diff = (timestamps[1] - timestamps[0]) * static_cast<u64>(m_device_properties.limits.timestampPeriod);
|
||||
m_accumulated_gpu_time += static_cast<double>(ns_diff) / 1000000.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkGetQueryPoolResults failed: ");
|
||||
}
|
||||
|
||||
vkCmdResetQueryPool(m_current_command_buffer, m_timestamp_query_pool, index * 2, 2);
|
||||
vkCmdWriteTimestamp(m_current_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool, index * 2);
|
||||
}
|
||||
}
|
||||
|
||||
void Context::ExecuteCommandBuffer(bool wait_for_completion)
|
||||
|
||||
+10
-2
@@ -208,6 +208,9 @@ namespace Vulkan
|
||||
|
||||
void WaitForGPUIdle();
|
||||
|
||||
float GetAndResetAccumulatedGPUTime();
|
||||
void SetEnableGPUTiming(bool enabled);
|
||||
|
||||
private:
|
||||
Context(VkInstance instance, VkPhysicalDevice physical_device);
|
||||
|
||||
@@ -284,14 +287,19 @@ namespace Vulkan
|
||||
VkDescriptorPool m_global_descriptor_pool = VK_NULL_HANDLE;
|
||||
|
||||
VkQueue m_graphics_queue = VK_NULL_HANDLE;
|
||||
u32 m_graphics_queue_family_index = 0;
|
||||
VkQueue m_present_queue = VK_NULL_HANDLE;
|
||||
u32 m_graphics_queue_family_index = 0;
|
||||
u32 m_present_queue_family_index = 0;
|
||||
|
||||
VkQueryPool m_timestamp_query_pool = VK_NULL_HANDLE;
|
||||
float m_accumulated_gpu_time = 0.0f;
|
||||
bool m_gpu_timing_enabled = false;
|
||||
bool m_gpu_timing_supported = false;
|
||||
|
||||
std::array<FrameResources, NUM_COMMAND_BUFFERS> m_frame_resources;
|
||||
u64 m_next_fence_counter = 1;
|
||||
u64 m_completed_fence_counter = 0;
|
||||
u32 m_current_frame;
|
||||
u32 m_current_frame = 0;
|
||||
|
||||
StreamBuffer m_texture_upload_buffer;
|
||||
|
||||
|
||||
@@ -78,7 +78,6 @@
|
||||
<ClCompile Include="Vulkan\Texture.cpp" />
|
||||
<ClCompile Include="Vulkan\Util.cpp" />
|
||||
<ClCompile Include="WindowInfo.cpp" />
|
||||
<ClCompile Include="x86\MemcpyFast.cpp" />
|
||||
<ClCompile Include="PathUtils.cpp" />
|
||||
<ClCompile Include="Perf.cpp" />
|
||||
<ClCompile Include="PrecompiledHeader.cpp">
|
||||
|
||||
@@ -49,9 +49,6 @@
|
||||
<ClCompile Include="Linux\LnxThreads.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="x86\MemcpyFast.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emitter\movs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace x86Emitter
|
||||
{
|
||||
if (sibdest.Is8BitOp())
|
||||
{
|
||||
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest);
|
||||
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest, 1);
|
||||
|
||||
xWrite<s8>(imm);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Devel|Win32">
|
||||
<Configuration>Devel</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Devel|x64">
|
||||
<Configuration>Devel</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
|
||||
@@ -1,26 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug AVX2|Win32">
|
||||
<Configuration>Debug AVX2</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug AVX2|x64">
|
||||
<Configuration>Debug AVX2</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Devel AVX2|Win32">
|
||||
<Configuration>Devel AVX2</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Devel AVX2|x64">
|
||||
<Configuration>Devel AVX2</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release AVX2|Win32">
|
||||
<Configuration>Release AVX2</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release AVX2|x64">
|
||||
<Configuration>Release AVX2</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
// GH: AMD memcpy was removed. The remaining part (memcmp_mmx) is likely from Zerofrog.
|
||||
// Hopefully memcmp_mmx will be dropped in the future.
|
||||
|
||||
#if defined(_WIN32) && !defined(_M_AMD64)
|
||||
#include "common/MemcpyFast.h"
|
||||
#include "common/Assertions.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4414)
|
||||
#endif
|
||||
|
||||
// Inline assembly syntax for use with Visual C++
|
||||
|
||||
// mmx mem-compare implementation, size has to be a multiple of 8
|
||||
// returns 0 is equal, nonzero value if not equal
|
||||
// ~10 times faster than standard memcmp
|
||||
// (zerofrog)
|
||||
u8 memcmp_mmx(const void *src1, const void *src2, int cmpsize)
|
||||
{
|
||||
pxAssert((cmpsize & 7) == 0);
|
||||
|
||||
__asm {
|
||||
mov ecx, cmpsize
|
||||
mov edx, src1
|
||||
mov esi, src2
|
||||
|
||||
cmp ecx, 32
|
||||
jl Done4
|
||||
|
||||
// custom test first 8 to make sure things are ok
|
||||
movq mm0, [esi]
|
||||
movq mm1, [esi+8]
|
||||
pcmpeqd mm0, [edx]
|
||||
pcmpeqd mm1, [edx+8]
|
||||
pand mm0, mm1
|
||||
movq mm2, [esi+16]
|
||||
pmovmskb eax, mm0
|
||||
movq mm3, [esi+24]
|
||||
|
||||
// check if eq
|
||||
cmp eax, 0xff
|
||||
je NextComp
|
||||
mov eax, 1
|
||||
jmp End
|
||||
|
||||
NextComp:
|
||||
pcmpeqd mm2, [edx+16]
|
||||
pcmpeqd mm3, [edx+24]
|
||||
pand mm2, mm3
|
||||
pmovmskb eax, mm2
|
||||
|
||||
sub ecx, 32
|
||||
add esi, 32
|
||||
add edx, 32
|
||||
|
||||
// check if eq
|
||||
cmp eax, 0xff
|
||||
je ContinueTest
|
||||
mov eax, 1
|
||||
jmp End
|
||||
|
||||
cmp ecx, 64
|
||||
jl Done8
|
||||
|
||||
Cmp8:
|
||||
movq mm0, [esi]
|
||||
movq mm1, [esi+8]
|
||||
movq mm2, [esi+16]
|
||||
movq mm3, [esi+24]
|
||||
movq mm4, [esi+32]
|
||||
movq mm5, [esi+40]
|
||||
movq mm6, [esi+48]
|
||||
movq mm7, [esi+56]
|
||||
pcmpeqd mm0, [edx]
|
||||
pcmpeqd mm1, [edx+8]
|
||||
pcmpeqd mm2, [edx+16]
|
||||
pcmpeqd mm3, [edx+24]
|
||||
pand mm0, mm1
|
||||
pcmpeqd mm4, [edx+32]
|
||||
pand mm0, mm2
|
||||
pcmpeqd mm5, [edx+40]
|
||||
pand mm0, mm3
|
||||
pcmpeqd mm6, [edx+48]
|
||||
pand mm0, mm4
|
||||
pcmpeqd mm7, [edx+56]
|
||||
pand mm0, mm5
|
||||
pand mm0, mm6
|
||||
pand mm0, mm7
|
||||
pmovmskb eax, mm0
|
||||
|
||||
// check if eq
|
||||
cmp eax, 0xff
|
||||
je Continue
|
||||
mov eax, 1
|
||||
jmp End
|
||||
|
||||
Continue:
|
||||
sub ecx, 64
|
||||
add esi, 64
|
||||
add edx, 64
|
||||
ContinueTest:
|
||||
cmp ecx, 64
|
||||
jge Cmp8
|
||||
|
||||
Done8:
|
||||
test ecx, 0x20
|
||||
jz Done4
|
||||
movq mm0, [esi]
|
||||
movq mm1, [esi+8]
|
||||
movq mm2, [esi+16]
|
||||
movq mm3, [esi+24]
|
||||
pcmpeqd mm0, [edx]
|
||||
pcmpeqd mm1, [edx+8]
|
||||
pcmpeqd mm2, [edx+16]
|
||||
pcmpeqd mm3, [edx+24]
|
||||
pand mm0, mm1
|
||||
pand mm0, mm2
|
||||
pand mm0, mm3
|
||||
pmovmskb eax, mm0
|
||||
sub ecx, 32
|
||||
add esi, 32
|
||||
add edx, 32
|
||||
|
||||
// check if eq
|
||||
cmp eax, 0xff
|
||||
je Done4
|
||||
mov eax, 1
|
||||
jmp End
|
||||
|
||||
Done4:
|
||||
cmp ecx, 24
|
||||
jne Done2
|
||||
movq mm0, [esi]
|
||||
movq mm1, [esi+8]
|
||||
movq mm2, [esi+16]
|
||||
pcmpeqd mm0, [edx]
|
||||
pcmpeqd mm1, [edx+8]
|
||||
pcmpeqd mm2, [edx+16]
|
||||
pand mm0, mm1
|
||||
pand mm0, mm2
|
||||
pmovmskb eax, mm0
|
||||
|
||||
// check if eq
|
||||
cmp eax, 0xff
|
||||
setne al
|
||||
jmp End
|
||||
|
||||
Done2:
|
||||
cmp ecx, 16
|
||||
jne Done1
|
||||
|
||||
movq mm0, [esi]
|
||||
movq mm1, [esi+8]
|
||||
pcmpeqd mm0, [edx]
|
||||
pcmpeqd mm1, [edx+8]
|
||||
pand mm0, mm1
|
||||
pmovmskb eax, mm0
|
||||
|
||||
// check if eq
|
||||
cmp eax, 0xff
|
||||
setne al
|
||||
jmp End
|
||||
|
||||
Done1:
|
||||
cmp ecx, 8
|
||||
jne Done
|
||||
|
||||
mov eax, [esi]
|
||||
mov esi, [esi+4]
|
||||
cmp eax, [edx]
|
||||
je Next
|
||||
mov eax, 1
|
||||
jmp End
|
||||
|
||||
Next:
|
||||
cmp esi, [edx+4]
|
||||
setne al
|
||||
jmp End
|
||||
|
||||
Done:
|
||||
xor eax, eax
|
||||
|
||||
End:
|
||||
emms
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "pcsx2/Frontend/InputManager.h"
|
||||
#include "pcsx2/Frontend/ImGuiManager.h"
|
||||
#include "pcsx2/GS.h"
|
||||
#include "pcsx2/GSDumpReplayer.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/PAD/Host/PAD.h"
|
||||
#include "pcsx2/PerformanceMetrics.h"
|
||||
@@ -677,6 +678,9 @@ bool Host::BeginPresentFrame(bool frame_skip)
|
||||
|
||||
void Host::EndPresentFrame()
|
||||
{
|
||||
if (GSDumpReplayer::IsReplayingDump())
|
||||
GSDumpReplayer::RenderUI();
|
||||
|
||||
ImGuiManager::RenderOSD();
|
||||
s_host_display->EndPresent();
|
||||
ImGuiManager::NewFrame();
|
||||
|
||||
+13
-9
@@ -41,7 +41,9 @@ static void PrintCommandLineHelp(const char* progname)
|
||||
std::fprintf(stderr, "\n");
|
||||
std::fprintf(stderr, " -help: Displays this information and exits.\n");
|
||||
std::fprintf(stderr, " -version: Displays version information and exits.\n");
|
||||
std::fprintf(stderr, " -batch: Enables batch mode (exits after powering off).\n");
|
||||
std::fprintf(stderr, " -batch: Enables batch mode (exits after shutting down).\n");
|
||||
std::fprintf(stderr, " -elf <file>: Overrides the boot ELF with the specified filename.\n");
|
||||
std::fprintf(stderr, " -disc <path>: Uses the specified host DVD drive as a source.\n");
|
||||
std::fprintf(stderr, " -fastboot: Force fast boot for provided filename.\n");
|
||||
std::fprintf(stderr, " -slowboot: Force slow boot for provided filename.\n");
|
||||
std::fprintf(stderr, " -resume: Load resume save state. If a boot filename is provided,\n"
|
||||
@@ -64,10 +66,8 @@ static void PrintCommandLineHelp(const char* progname)
|
||||
static std::shared_ptr<VMBootParameters>& AutoBoot(std::shared_ptr<VMBootParameters>& autoboot)
|
||||
{
|
||||
if (!autoboot)
|
||||
{
|
||||
autoboot = std::make_shared<VMBootParameters>();
|
||||
autoboot->source_type = CDVD_SourceType::NoDisc;
|
||||
}
|
||||
|
||||
return autoboot;
|
||||
}
|
||||
|
||||
@@ -134,6 +134,12 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
||||
AutoBoot(autoboot)->elf_override = argv[++i];
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-disc"))
|
||||
{
|
||||
AutoBoot(autoboot)->source_type = CDVD_SourceType::Disc;
|
||||
AutoBoot(autoboot)->filename = argv[++i];
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG("-fullscreen"))
|
||||
{
|
||||
Console.WriteLn("Going fullscreen after booting.");
|
||||
@@ -172,12 +178,10 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
||||
#undef CHECK_ARG_PARAM
|
||||
}
|
||||
|
||||
if (!AutoBoot(autoboot)->source.empty())
|
||||
AutoBoot(autoboot)->source += ' ';
|
||||
else
|
||||
AutoBoot(autoboot)->source_type = CDVD_SourceType::Iso;
|
||||
if (!AutoBoot(autoboot)->filename.empty())
|
||||
AutoBoot(autoboot)->filename += ' ';
|
||||
|
||||
AutoBoot(autoboot)->source += argv[i];
|
||||
AutoBoot(autoboot)->filename += argv[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+55
-17
@@ -44,9 +44,15 @@
|
||||
#include "svnrev.h"
|
||||
|
||||
static constexpr char DISC_IMAGE_FILTER[] =
|
||||
QT_TRANSLATE_NOOP("MainWindow", "All File Types (*.bin *.iso *.cue *.chd *.cso *.elf *.irx *.m3u);;Single-Track Raw Images (*.bin "
|
||||
"*.iso);;Cue Sheets (*.cue);;MAME CHD Images (*.chd);;CSO Images (*.cso);;"
|
||||
"ELF Executables (*.elf);;IRX Executables (*.irx);;Playlists (*.m3u)");
|
||||
QT_TRANSLATE_NOOP("MainWindow", "All File Types (*.bin *.iso *.cue *.chd *.cso *.elf *.irx *.m3u *.gs *.gs.xz);;"
|
||||
"Single-Track Raw Images (*.bin *.iso);;"
|
||||
"Cue Sheets (*.cue);;"
|
||||
"MAME CHD Images (*.chd);;"
|
||||
"CSO Images (*.cso);;"
|
||||
"ELF Executables (*.elf);;"
|
||||
"IRX Executables (*.irx);;"
|
||||
"Playlists (*.m3u);;"
|
||||
"GS Dumps (*.gs *.gs.xz)");
|
||||
|
||||
const char* MainWindow::DEFAULT_THEME_NAME = "darkfusion";
|
||||
|
||||
@@ -602,7 +608,10 @@ void MainWindow::clearProgressBar()
|
||||
m_ui.statusBar->removeWidget(m_status_progress_widget);
|
||||
}
|
||||
|
||||
bool MainWindow::isShowingGameList() const { return m_ui.mainContainer->currentIndex() == 0; }
|
||||
bool MainWindow::isShowingGameList() const
|
||||
{
|
||||
return m_ui.mainContainer->currentIndex() == 0;
|
||||
}
|
||||
|
||||
void MainWindow::switchToGameListView()
|
||||
{
|
||||
@@ -635,11 +644,20 @@ void MainWindow::switchToEmulationView()
|
||||
m_display_widget->setFocus();
|
||||
}
|
||||
|
||||
void MainWindow::refreshGameList(bool invalidate_cache) { m_game_list_widget->refresh(invalidate_cache); }
|
||||
void MainWindow::refreshGameList(bool invalidate_cache)
|
||||
{
|
||||
m_game_list_widget->refresh(invalidate_cache);
|
||||
}
|
||||
|
||||
void MainWindow::invalidateSaveStateCache() { m_save_states_invalidated = true; }
|
||||
void MainWindow::invalidateSaveStateCache()
|
||||
{
|
||||
m_save_states_invalidated = true;
|
||||
}
|
||||
|
||||
void MainWindow::reportError(const QString& title, const QString& message) { QMessageBox::critical(this, title, message); }
|
||||
void MainWindow::reportError(const QString& title, const QString& message)
|
||||
{
|
||||
QMessageBox::critical(this, title, message);
|
||||
}
|
||||
|
||||
bool MainWindow::confirmShutdown()
|
||||
{
|
||||
@@ -660,7 +678,10 @@ void MainWindow::requestExit()
|
||||
close();
|
||||
}
|
||||
|
||||
void Host::InvalidateSaveStateCache() { QMetaObject::invokeMethod(g_main_window, &MainWindow::invalidateSaveStateCache, Qt::QueuedConnection); }
|
||||
void Host::InvalidateSaveStateCache()
|
||||
{
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::invalidateSaveStateCache, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void MainWindow::onGameListRefreshProgress(const QString& status, int current, int total)
|
||||
{
|
||||
@@ -668,7 +689,10 @@ void MainWindow::onGameListRefreshProgress(const QString& status, int current, i
|
||||
setProgressBar(current, total);
|
||||
}
|
||||
|
||||
void MainWindow::onGameListRefreshComplete() { clearProgressBar(); }
|
||||
void MainWindow::onGameListRefreshComplete()
|
||||
{
|
||||
clearProgressBar();
|
||||
}
|
||||
|
||||
void MainWindow::onGameListSelectionChanged()
|
||||
{
|
||||
@@ -779,14 +803,13 @@ void MainWindow::onStartFileActionTriggered()
|
||||
return;
|
||||
|
||||
std::shared_ptr<VMBootParameters> params = std::make_shared<VMBootParameters>();
|
||||
VMManager::SetBootParametersForPath(filename.toStdString(), params.get());
|
||||
params->filename = filename.toStdString();
|
||||
g_emu_thread->startVM(std::move(params));
|
||||
}
|
||||
|
||||
void MainWindow::onStartBIOSActionTriggered()
|
||||
{
|
||||
std::shared_ptr<VMBootParameters> params = std::make_shared<VMBootParameters>();
|
||||
params->source_type = CDVD_SourceType::NoDisc;
|
||||
g_emu_thread->startVM(std::move(params));
|
||||
}
|
||||
|
||||
@@ -801,7 +824,10 @@ void MainWindow::onChangeDiscFromFileActionTriggered()
|
||||
g_emu_thread->changeDisc(filename);
|
||||
}
|
||||
|
||||
void MainWindow::onChangeDiscFromGameListActionTriggered() { switchToGameListView(); }
|
||||
void MainWindow::onChangeDiscFromGameListActionTriggered()
|
||||
{
|
||||
switchToGameListView();
|
||||
}
|
||||
|
||||
void MainWindow::onChangeDiscFromDeviceActionTriggered()
|
||||
{
|
||||
@@ -885,11 +911,20 @@ void MainWindow::onViewGamePropertiesActionTriggered()
|
||||
SettingsDialog::openGamePropertiesDialog(nullptr, m_current_game_crc);
|
||||
}
|
||||
|
||||
void MainWindow::onGitHubRepositoryActionTriggered() { QtUtils::OpenURL(this, AboutDialog::getGitHubRepositoryUrl()); }
|
||||
void MainWindow::onGitHubRepositoryActionTriggered()
|
||||
{
|
||||
QtUtils::OpenURL(this, AboutDialog::getGitHubRepositoryUrl());
|
||||
}
|
||||
|
||||
void MainWindow::onSupportForumsActionTriggered() { QtUtils::OpenURL(this, AboutDialog::getSupportForumsUrl()); }
|
||||
void MainWindow::onSupportForumsActionTriggered()
|
||||
{
|
||||
QtUtils::OpenURL(this, AboutDialog::getSupportForumsUrl());
|
||||
}
|
||||
|
||||
void MainWindow::onDiscordServerActionTriggered() { QtUtils::OpenURL(this, AboutDialog::getDiscordServerUrl()); }
|
||||
void MainWindow::onDiscordServerActionTriggered()
|
||||
{
|
||||
QtUtils::OpenURL(this, AboutDialog::getDiscordServerUrl());
|
||||
}
|
||||
|
||||
void MainWindow::onAboutActionTriggered()
|
||||
{
|
||||
@@ -1191,7 +1226,10 @@ void MainWindow::displayResizeRequested(qint32 width, qint32 height)
|
||||
resize(QSize(std::max<qint32>(width, 1), std::max<qint32>(height + extra_height, 1)));
|
||||
}
|
||||
|
||||
void MainWindow::destroyDisplay() { destroyDisplayWidget(); }
|
||||
void MainWindow::destroyDisplay()
|
||||
{
|
||||
destroyDisplayWidget();
|
||||
}
|
||||
|
||||
void MainWindow::focusDisplayWidget()
|
||||
{
|
||||
@@ -1398,7 +1436,7 @@ void MainWindow::loadSaveStateFile(const QString& filename, const QString& state
|
||||
else
|
||||
{
|
||||
std::shared_ptr<VMBootParameters> params = std::make_shared<VMBootParameters>();
|
||||
VMManager::SetBootParametersForPath(filename.toStdString(), params.get());
|
||||
params->filename = filename.toStdString();
|
||||
params->save_state = state_filename.toStdString();
|
||||
g_emu_thread->startVM(std::move(params));
|
||||
}
|
||||
|
||||
+2
-2
@@ -313,13 +313,13 @@ void Host::ReportErrorAsync(const std::string_view& title, const std::string_vie
|
||||
{
|
||||
if (!title.empty() && !message.empty())
|
||||
{
|
||||
Console.Error("ReportErrorAsync: %*s: %*s",
|
||||
Console.Error("ReportErrorAsync: %.*s: %.*s",
|
||||
static_cast<int>(title.size()), title.data(),
|
||||
static_cast<int>(message.size()), message.data());
|
||||
}
|
||||
else if (!message.empty())
|
||||
{
|
||||
Console.Error("ReportErrorAsync: %*s",
|
||||
Console.Error("ReportErrorAsync: %.*s",
|
||||
static_cast<int>(message.size()), message.data());
|
||||
}
|
||||
|
||||
|
||||
@@ -435,7 +435,7 @@ namespace SettingWidgetBinder
|
||||
|
||||
int sif_value;
|
||||
if (sif->GetIntValue(section.c_str(), key.c_str(), &sif_value))
|
||||
Accessor::setNullableIntValue(widget, sif_value);
|
||||
Accessor::setNullableIntValue(widget, sif_value - option_offset);
|
||||
else
|
||||
Accessor::setNullableIntValue(widget, std::nullopt);
|
||||
|
||||
@@ -735,7 +735,7 @@ namespace SettingWidgetBinder
|
||||
{
|
||||
for (int i = 0; enum_values[i] != nullptr; i++)
|
||||
{
|
||||
if (value == enum_values[i])
|
||||
if (sif_value == enum_values[i])
|
||||
{
|
||||
sif_int_value = i;
|
||||
break;
|
||||
@@ -744,9 +744,9 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
Accessor::setNullableIntValue(widget, sif_int_value);
|
||||
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key), enum_names]() {
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key), enum_values]() {
|
||||
if (std::optional<int> new_value = Accessor::getNullableIntValue(widget); new_value.has_value())
|
||||
sif->SetStringValue(section.c_str(), key.c_str(), enum_names[new_value.value()]);
|
||||
sif->SetStringValue(section.c_str(), key.c_str(), enum_values[new_value.value()]);
|
||||
else
|
||||
sif->DeleteValue(section.c_str(), key.c_str());
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ void ControllerBindingWidget_Base::initBindingWidgets()
|
||||
InputBindingWidget* widget = findChild<InputBindingWidget*>(QString::fromStdString(binding));
|
||||
if (!widget)
|
||||
{
|
||||
Console.Error("(ControllerBindingWidget_Base) No widget found for '%s' (%*s)",
|
||||
Console.Error("(ControllerBindingWidget_Base) No widget found for '%s' (%.*s)",
|
||||
binding.c_str(), static_cast<int>(type.size()), type.data());
|
||||
continue;
|
||||
}
|
||||
@@ -155,4 +155,4 @@ ControllerBindingWidget_Base* ControllerBindingWidget_DualShock2::createInstance
|
||||
return new ControllerBindingWidget_DualShock2(parent);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -104,6 +104,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowSpeed, "EmuCore/GS", "OsdShowSpeed", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowFPS, "EmuCore/GS", "OsdShowFPS", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowCPU, "EmuCore/GS", "OsdShowCPU", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowGPU, "EmuCore/GS", "OsdShowGPU", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowResolution, "EmuCore/GS", "OsdShowResolution", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowGSStats, "EmuCore/GS", "OsdShowGSStats", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowIndicators, "EmuCore/GS", "OsdShowIndicators", true);
|
||||
@@ -141,22 +142,22 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
// HW Renderer Fixes
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.halfScreenFix, "EmuCore/GS", "UserHacks_Half_Bottom_Override", -1, -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawRangeStart, "EmuCore/GS", "UserHacks_SkipDraw", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawRangeCount, "EmuCore/GS", "UserHacks_SkipDraw_Offset", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawStart, "EmuCore/GS", "UserHacks_SkipDraw_Start", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawEnd, "EmuCore/GS", "UserHacks_SkipDraw_End", 0);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hwAutoFlush, "EmuCore/GS", "UserHacks_AutoFlush", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.frameBufferConversion, "EmuCore/GS", "UserHacks_CPU_FB_Conversion", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDepthEmulation, "EmuCore/GS", "UserHacks_DisableDepthSupport", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.memoryWrapping, "EmuCore/GS", "wrap_gs_mem", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableSafeFeatures, "EmuCore/GS", "UserHacks_Disable_Safe_Features", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.preloadFrameData, "EmuCore/GS", "preload_frame_with_gs_data", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastTextureInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disablePartialInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.textureInsideRt, "EmuCore/GS", "UserHacks_TextureInsideRt", false);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// HW Upscaling Fixes
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.halfPixelOffset, "EmuCore/GS", "UserHacks_HalfPixelOffset", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.roundSprite, "EmuCore/GS", "UserHacks_RoundSprite", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.roundSprite, "EmuCore/GS", "UserHacks_round_sprite_offset", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureOffsetX, "EmuCore/GS", "UserHacks_TCOffsetX", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureOffsetY, "EmuCore/GS", "UserHacks_TCOffsetY", 0);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.alignSprite, "EmuCore/GS", "UserHacks_align_sprite_X", false);
|
||||
|
||||
@@ -586,7 +586,7 @@
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="enableHWFixes">
|
||||
<property name="text">
|
||||
<string>Enable Hardware Renderer Fixes</string>
|
||||
<string>Manual Hardware Renderer Fixes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -661,10 +661,18 @@
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawRangeStart"/>
|
||||
<widget class="QSpinBox" name="skipDrawStart">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawRangeCount"/>
|
||||
<widget class="QSpinBox" name="skipDrawEnd">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
@@ -713,9 +721,9 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="fastTextureInvalidation">
|
||||
<widget class="QCheckBox" name="disablePartialInvalidation">
|
||||
<property name="text">
|
||||
<string>Fast Texture Invalidation</string>
|
||||
<string>Disable Partial Invalidation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -809,7 +817,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="textureOffsetX"/>
|
||||
<widget class="QSpinBox" name="textureOffsetX">
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_18">
|
||||
@@ -819,7 +831,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="textureOffsetY"/>
|
||||
<widget class="QSpinBox" name="textureOffsetY">
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
@@ -913,13 +929,20 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="osdShowGPU">
|
||||
<property name="text">
|
||||
<string>Show GPU Usage</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="osdShowGSStats">
|
||||
<property name="text">
|
||||
<string>Show Statistics</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="osdShowIndicators">
|
||||
<property name="text">
|
||||
<string>Show Indicators</string>
|
||||
|
||||
@@ -390,7 +390,7 @@ void SettingsDialog::setStringSettingValue(const char* section, const char* key,
|
||||
{
|
||||
if (m_sif)
|
||||
{
|
||||
value.has_value() ? m_sif->SetBoolValue(section, key, value.value()) : m_sif->DeleteValue(section, key);
|
||||
value.has_value() ? m_sif->SetStringValue(section, key, value.value()) : m_sif->DeleteValue(section, key);
|
||||
m_sif->Save();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -983,6 +983,7 @@ if(PCSX2_CORE)
|
||||
Frontend/InputManager.cpp
|
||||
Frontend/InputSource.cpp
|
||||
Frontend/LayeredSettingsInterface.cpp
|
||||
GSDumpReplayer.cpp
|
||||
HostSettings.cpp
|
||||
VMManager.cpp
|
||||
)
|
||||
@@ -992,6 +993,7 @@ if(PCSX2_CORE)
|
||||
Frontend/InputManager.h
|
||||
Frontend/InputSource.h
|
||||
Frontend/LayeredSettingsInterface.h
|
||||
GSDumpReplayer.h
|
||||
HostSettings.h
|
||||
VMManager.h)
|
||||
endif()
|
||||
|
||||
+10
-4
@@ -58,6 +58,7 @@ enum SpeedhackId
|
||||
|
||||
Speedhack_mvuFlag = SpeedhackId_FIRST,
|
||||
Speedhack_InstantVU1,
|
||||
Speedhack_MTVU,
|
||||
|
||||
SpeedhackId_COUNT
|
||||
};
|
||||
@@ -427,6 +428,7 @@ struct Pcsx2Config
|
||||
OsdShowSpeed : 1,
|
||||
OsdShowFPS : 1,
|
||||
OsdShowCPU : 1,
|
||||
OsdShowGPU : 1,
|
||||
OsdShowResolution : 1,
|
||||
OsdShowGSStats : 1,
|
||||
OsdShowIndicators : 1;
|
||||
@@ -441,7 +443,8 @@ struct Pcsx2Config
|
||||
WrapGSMem : 1,
|
||||
Mipmap : 1,
|
||||
AA1 : 1,
|
||||
UserHacks : 1,
|
||||
PointListPalette : 1,
|
||||
ManualUserHacks : 1,
|
||||
UserHacks_AlignSpriteX : 1,
|
||||
UserHacks_AutoFlush : 1,
|
||||
UserHacks_CPUFBConversion : 1,
|
||||
@@ -509,8 +512,8 @@ struct Pcsx2Config
|
||||
int SWExtraThreads{2};
|
||||
int SWExtraThreadsHeight{4};
|
||||
int TVShader{0};
|
||||
int SkipDraw{0};
|
||||
int SkipDrawOffset{0};
|
||||
int SkipDrawStart{0};
|
||||
int SkipDrawEnd{0};
|
||||
|
||||
int UserHacks_HalfBottomOverride{-1};
|
||||
int UserHacks_HalfPixelOffset{0};
|
||||
@@ -543,6 +546,9 @@ struct Pcsx2Config
|
||||
/// Sets user hack values to defaults when user hacks are not enabled.
|
||||
void MaskUserHacks();
|
||||
|
||||
/// Sets user hack values to defaults when upscaling is not enabled.
|
||||
void MaskUpscalingHacks();
|
||||
|
||||
/// Returns true if any of the hardware renderers are selected.
|
||||
bool UseHardwareRenderer() const;
|
||||
|
||||
@@ -668,7 +674,7 @@ struct Pcsx2Config
|
||||
* which is 2^32 * 512 byte sectors
|
||||
* Note that we don't yet support
|
||||
* 48bit LBA, so our limit is lower */
|
||||
uint HddSizeSectors{0};
|
||||
uint HddSizeSectors{40 * (1024 * 1024 * 1024 / 512)};
|
||||
|
||||
DEV9Options();
|
||||
|
||||
|
||||
+45
-7
@@ -48,7 +48,7 @@ SERIAL-12345: # !required! Serial number for the game, this is how games are loo
|
||||
memcardFilters:
|
||||
- "SERIAL-123"
|
||||
- "SERIAL-456"
|
||||
# You can define multple patches, but they are identified by the CRC.
|
||||
# You can define multiple patches, but they are identified by the CRC.
|
||||
patches:
|
||||
default: # Default CRC!
|
||||
author: "Some Person"
|
||||
@@ -124,6 +124,44 @@ The clamp modes are also numerically based.
|
||||
* `2` = Clamp **Extra** (clamp results as well as operands)
|
||||
* `3` = Clamp **Extra+Preserve Sign**
|
||||
|
||||
## GS Hardware Fixes
|
||||
|
||||
[ ] = GameDB values
|
||||
{ } = GUI options
|
||||
( ) = Default values
|
||||
|
||||
### GS Hardware Mipmap Fixes
|
||||
|
||||
* mipmap [`0` or `1` or `2`] {Off, Basic, Full} Default: Automatic (No value, looks up GameDB)
|
||||
* trilinearFiltering [`0` or `1` or `2`] {None, Trilinear, Trilinear Ultra} Default: None (`0`)
|
||||
|
||||
### GS Hardware General Fixes
|
||||
|
||||
* conservativeFramebuffer [`0` or `1`] {Off or On} Default: On (`1`)
|
||||
* texturePreloading [`0` or `1` or `2`] {None, Partial or Full Hash Cache} Default: None (`0`)
|
||||
|
||||
### GS Hardware Renderer Fixes
|
||||
|
||||
* autoFlush [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* disableDepthSupport [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* disablePartialInvalidation [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* cpuFramebufferConversion [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* wrapGSMem [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* preloadFrameData [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* textureInsideRT [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* halfBottomOverride [`0` or `1`] {Force-Disabled or Force-Enabled} Default: Automatic (No value, looks up GameDB)
|
||||
* pointListPalette [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
|
||||
### GS Hardware Upscaling Fixes
|
||||
|
||||
* alignSprite [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* mergeSprite [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* wildArmsHack [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* skipDrawStart [Value between `0` to `100000`] {0-100000} Default: Off (`0`)
|
||||
* skipDrawEnd [Value between `0` to `100000`] {0-100000} Default: Off (`0`)
|
||||
* halfPixelOffset [`0` or `1` or `2` or `3`] {Off, Normal Vertex, Special Texture or Special Texture Aggressive} Default: Off (`0`)
|
||||
* roundSprite [`0` or `1` or `2`] {Off, Half or Full} Default: Off (`0`)
|
||||
|
||||
## Game Fixes
|
||||
|
||||
These values are case-sensitive so take care. If you incorrectly specify a GameFix, you will get a validation error on startup. Any invalid game-fixes will be dropped from the game's list of fixes.
|
||||
@@ -184,12 +222,12 @@ These values are in a key-value format, where the value is assumed to be an inte
|
||||
* `mvuFlagSpeedHack`
|
||||
* Accepted Values - `0` / `1`
|
||||
* Katamari Damacy have weird speed bug when this speed hack is enabled (and it is by default)
|
||||
|
||||
<!-- [list-item-spacing] Missing new line after list item->
|
||||
|
||||
- `InstantVU1SpeedHack`
|
||||
- Accepted Values - `0` / `1`
|
||||
- Games such as Parappa the Rapper 2 need VU1 to sync, so you can force disable the speedhack here
|
||||
* `MTVUSpeedHack`
|
||||
* Accepted Values - `0` / `1`
|
||||
* T-bit games dislike MTVU and some games are incompatible with MTVU.
|
||||
* `InstantVU1SpeedHack`
|
||||
* Accepted Values - `0` / `1`
|
||||
* Games such as Parappa the Rapper 2 need VU1 to sync, so you can force sync with this parameter.
|
||||
|
||||
## Memory Card Filter Override
|
||||
|
||||
|
||||
@@ -742,11 +742,122 @@ void D3D11HostDisplay::EndPresent()
|
||||
ImGui::Render();
|
||||
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
PopTimestampQuery();
|
||||
|
||||
const UINT vsync_rate = static_cast<UINT>(m_vsync_mode != VsyncMode::Off);
|
||||
if (vsync_rate == 0 && m_using_allow_tearing)
|
||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||
else
|
||||
m_swap_chain->Present(vsync_rate, 0);
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
KickTimestampQuery();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::CreateTimestampQueries()
|
||||
{
|
||||
for (u32 i = 0; i < NUM_TIMESTAMP_QUERIES; i++)
|
||||
{
|
||||
for (u32 j = 0; j < 3; j++)
|
||||
{
|
||||
const CD3D11_QUERY_DESC qdesc((j == 0) ? D3D11_QUERY_TIMESTAMP_DISJOINT : D3D11_QUERY_TIMESTAMP);
|
||||
const HRESULT hr = m_device->CreateQuery(&qdesc, m_timestamp_queries[i][j].ReleaseAndGetAddressOf());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
m_timestamp_queries = {};
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KickTimestampQuery();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::DestroyTimestampQueries()
|
||||
{
|
||||
if (!m_timestamp_queries[0][0])
|
||||
return;
|
||||
|
||||
if (m_timestamp_query_started)
|
||||
m_context->End(m_timestamp_queries[m_write_timestamp_query][1].Get());
|
||||
|
||||
m_timestamp_queries = {};
|
||||
m_read_timestamp_query = 0;
|
||||
m_write_timestamp_query = 0;
|
||||
m_waiting_timestamp_queries = 0;
|
||||
m_timestamp_query_started = 0;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::PopTimestampQuery()
|
||||
{
|
||||
while (m_waiting_timestamp_queries > 0)
|
||||
{
|
||||
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjoint;
|
||||
const HRESULT disjoint_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][0].Get(), &disjoint, sizeof(disjoint), D3D11_ASYNC_GETDATA_DONOTFLUSH);
|
||||
if (disjoint_hr != S_OK)
|
||||
break;
|
||||
|
||||
if (disjoint.Disjoint)
|
||||
{
|
||||
DevCon.WriteLn("GPU timing disjoint, resetting.");
|
||||
m_read_timestamp_query = 0;
|
||||
m_write_timestamp_query = 0;
|
||||
m_waiting_timestamp_queries = 0;
|
||||
m_timestamp_query_started = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 start = 0, end = 0;
|
||||
const HRESULT start_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][1].Get(), &start, sizeof(start), D3D11_ASYNC_GETDATA_DONOTFLUSH);
|
||||
const HRESULT end_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][2].Get(), &end, sizeof(end), D3D11_ASYNC_GETDATA_DONOTFLUSH);
|
||||
if (start_hr == S_OK && end_hr == S_OK)
|
||||
{
|
||||
m_accumulated_gpu_time += static_cast<float>(static_cast<double>(end - start) / (static_cast<double>(disjoint.Frequency) / 1000.0));
|
||||
m_read_timestamp_query = (m_read_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
|
||||
m_waiting_timestamp_queries--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delay ending the current query until we've read back some
|
||||
if (m_timestamp_query_started && m_waiting_timestamp_queries < (NUM_TIMESTAMP_QUERIES - 1))
|
||||
{
|
||||
m_context->End(m_timestamp_queries[m_write_timestamp_query][2].Get());
|
||||
m_context->End(m_timestamp_queries[m_write_timestamp_query][0].Get());
|
||||
m_write_timestamp_query = (m_write_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
|
||||
m_timestamp_query_started = false;
|
||||
m_waiting_timestamp_queries++;
|
||||
}
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::KickTimestampQuery()
|
||||
{
|
||||
if (m_timestamp_query_started)
|
||||
return;
|
||||
|
||||
m_context->Begin(m_timestamp_queries[m_write_timestamp_query][0].Get());
|
||||
m_context->End(m_timestamp_queries[m_write_timestamp_query][1].Get());
|
||||
m_timestamp_query_started = true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
{
|
||||
if (m_gpu_timing_enabled == enabled)
|
||||
return;
|
||||
|
||||
m_gpu_timing_enabled = enabled;
|
||||
if (m_gpu_timing_enabled)
|
||||
CreateTimestampQueries();
|
||||
else
|
||||
DestroyTimestampQueries();
|
||||
}
|
||||
|
||||
float D3D11HostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
{
|
||||
const float value = m_accumulated_gpu_time;
|
||||
m_accumulated_gpu_time = 0.0f;
|
||||
return value;
|
||||
}
|
||||
|
||||
HostDisplay::AdapterAndModeList D3D11HostDisplay::StaticGetAdapterAndModeList()
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "HostDisplay.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include "common/WindowInfo.h"
|
||||
#include <array>
|
||||
#include <d3d11.h>
|
||||
#include <dxgi.h>
|
||||
#include <memory>
|
||||
@@ -68,10 +69,14 @@ public:
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
||||
void SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
|
||||
protected:
|
||||
static constexpr u32 DISPLAY_CONSTANT_BUFFER_SIZE = 16;
|
||||
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
|
||||
|
||||
static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory);
|
||||
|
||||
@@ -82,6 +87,11 @@ protected:
|
||||
bool CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode);
|
||||
bool CreateSwapChainRTV();
|
||||
|
||||
void CreateTimestampQueries();
|
||||
void DestroyTimestampQueries();
|
||||
void PopTimestampQuery();
|
||||
void KickTimestampQuery();
|
||||
|
||||
ComPtr<ID3D11Device> m_device;
|
||||
ComPtr<ID3D11DeviceContext> m_context;
|
||||
|
||||
@@ -92,5 +102,13 @@ protected:
|
||||
bool m_allow_tearing_supported = false;
|
||||
bool m_using_flip_model_swap_chain = true;
|
||||
bool m_using_allow_tearing = false;
|
||||
|
||||
std::array<std::array<ComPtr<ID3D11Query>, 3>, NUM_TIMESTAMP_QUERIES> m_timestamp_queries = {};
|
||||
u8 m_read_timestamp_query = 0;
|
||||
u8 m_write_timestamp_query = 0;
|
||||
u8 m_waiting_timestamp_queries = 0;
|
||||
bool m_timestamp_query_started = false;
|
||||
float m_accumulated_gpu_time = 0.0f;
|
||||
bool m_gpu_timing_enabled = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -123,19 +123,19 @@ void GameList::FillBootParametersForEntry(VMBootParameters* params, const Entry*
|
||||
{
|
||||
if (entry->type == GameList::EntryType::PS1Disc || entry->type == GameList::EntryType::PS2Disc)
|
||||
{
|
||||
params->source = entry->path;
|
||||
params->filename = entry->path;
|
||||
params->source_type = CDVD_SourceType::Iso;
|
||||
params->elf_override.clear();
|
||||
}
|
||||
else if (entry->type == GameList::EntryType::ELF)
|
||||
{
|
||||
params->source.clear();
|
||||
params->filename.clear();
|
||||
params->source_type = CDVD_SourceType::NoDisc;
|
||||
params->elf_override = entry->path;
|
||||
}
|
||||
else
|
||||
{
|
||||
params->source.clear();
|
||||
params->filename.clear();
|
||||
params->source_type = CDVD_SourceType::NoDisc;
|
||||
params->elf_override.clear();
|
||||
}
|
||||
@@ -568,6 +568,17 @@ const GameList::Entry* GameList::GetEntryForPath(const char* path)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GameList::Entry* GameList::GetEntryByCRC(u32 crc)
|
||||
{
|
||||
for (const Entry& entry : m_entries)
|
||||
{
|
||||
if (entry.crc == crc)
|
||||
return &entry;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GameList::Entry* GameList::GetEntryBySerialAndCRC(const std::string_view& serial, u32 crc)
|
||||
{
|
||||
for (const Entry& entry : m_entries)
|
||||
|
||||
@@ -80,6 +80,7 @@ namespace GameList
|
||||
std::unique_lock<std::recursive_mutex> GetLock();
|
||||
const Entry* GetEntryByIndex(u32 index);
|
||||
const Entry* GetEntryForPath(const char* path);
|
||||
const Entry* GetEntryByCRC(u32 crc);
|
||||
const Entry* GetEntryBySerialAndCRC(const std::string_view& serial, u32 crc);
|
||||
u32 GetEntryCount();
|
||||
|
||||
|
||||
@@ -469,6 +469,17 @@ static void DrawOSDMessages()
|
||||
}
|
||||
}
|
||||
|
||||
static void FormatProcessorStat(FastFormatAscii& text, double usage, double time)
|
||||
{
|
||||
// Some values, such as GPU (and even CPU to some extent) can be out of phase with the wall clock,
|
||||
// which the processor time is divided by to get a utilization percentage. Let's clamp it at 100%,
|
||||
// so that people don't get confused, and remove the decimal places when it's there while we're at it.
|
||||
if (usage >= 99.95)
|
||||
text.Write("100%% (%.2fms)", time);
|
||||
else
|
||||
text.Write("%.1f%% (%.2fms)", usage, time);
|
||||
}
|
||||
|
||||
static void DrawPerformanceOverlay()
|
||||
{
|
||||
const float scale = s_global_scale;
|
||||
@@ -575,32 +586,43 @@ static void DrawPerformanceOverlay()
|
||||
|
||||
text.Clear();
|
||||
if (EmuConfig.Speedhacks.EECycleRate != 0 || EmuConfig.Speedhacks.EECycleSkip != 0)
|
||||
{
|
||||
text.Write("EE[%d/%d]: %.1f%% (%.2fms)", EmuConfig.Speedhacks.EECycleRate, EmuConfig.Speedhacks.EECycleSkip,
|
||||
PerformanceMetrics::GetCPUThreadUsage(),
|
||||
PerformanceMetrics::GetCPUThreadAverageTime());
|
||||
}
|
||||
text.Write("EE[%d/%d]: ", EmuConfig.Speedhacks.EECycleRate, EmuConfig.Speedhacks.EECycleSkip);
|
||||
else
|
||||
{
|
||||
text.Write("EE: %.1f%% (%.2fms)", PerformanceMetrics::GetCPUThreadUsage(),
|
||||
PerformanceMetrics::GetCPUThreadAverageTime());
|
||||
}
|
||||
text.Write("EE: ");
|
||||
FormatProcessorStat(text, PerformanceMetrics::GetCPUThreadUsage(), PerformanceMetrics::GetCPUThreadAverageTime());
|
||||
DRAW_LINE(s_fixed_font, text.c_str(), IM_COL32(255, 255, 255, 255));
|
||||
|
||||
text.Clear();
|
||||
text.Write("GS: %.1f%% (%.2fms)", PerformanceMetrics::GetGSThreadUsage(),
|
||||
PerformanceMetrics::GetGSThreadAverageTime());
|
||||
text.Write("GS: ");
|
||||
FormatProcessorStat(text, PerformanceMetrics::GetGSThreadUsage(), PerformanceMetrics::GetGSThreadAverageTime());
|
||||
DRAW_LINE(s_fixed_font, text.c_str(), IM_COL32(255, 255, 255, 255));
|
||||
|
||||
const u32 gs_sw_threads = PerformanceMetrics::GetGSSWThreadCount();
|
||||
for (u32 i = 0; i < gs_sw_threads; i++)
|
||||
{
|
||||
text.Clear();
|
||||
text.Write("SW-%u: ", i);
|
||||
FormatProcessorStat(text, PerformanceMetrics::GetGSSWThreadUsage(i), PerformanceMetrics::GetGSSWThreadAverageTime(i));
|
||||
DRAW_LINE(s_fixed_font, text.c_str(), IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
|
||||
if (THREAD_VU1)
|
||||
{
|
||||
text.Clear();
|
||||
text.Write("VU: %.1f%% (%.2fms)", PerformanceMetrics::GetVUThreadUsage(),
|
||||
PerformanceMetrics::GetVUThreadAverageTime());
|
||||
text.Write("VU: ");
|
||||
FormatProcessorStat(text, PerformanceMetrics::GetVUThreadUsage(), PerformanceMetrics::GetVUThreadAverageTime());
|
||||
DRAW_LINE(s_fixed_font, text.c_str(), IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
|
||||
if (GSConfig.OsdShowGPU)
|
||||
{
|
||||
text.Clear();
|
||||
text.Write("GPU: ");
|
||||
FormatProcessorStat(text, PerformanceMetrics::GetGPUUsage(), PerformanceMetrics::GetGPUAverageTime());
|
||||
DRAW_LINE(s_fixed_font, text.c_str(), IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
|
||||
if (GSConfig.OsdShowIndicators)
|
||||
{
|
||||
const bool is_normal_speed = (EmuConfig.GS.LimitScalar == EmuConfig.Framerate.NominalScalar);
|
||||
@@ -630,3 +652,17 @@ void ImGuiManager::RenderOSD()
|
||||
DrawOSDMessages();
|
||||
}
|
||||
|
||||
float ImGuiManager::GetGlobalScale()
|
||||
{
|
||||
return s_global_scale;
|
||||
}
|
||||
|
||||
ImFont* ImGuiManager::GetStandardFont()
|
||||
{
|
||||
return s_standard_font;
|
||||
}
|
||||
|
||||
ImFont* ImGuiManager::GetFixedFont()
|
||||
{
|
||||
return s_fixed_font;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ImFont;
|
||||
|
||||
namespace ImGuiManager
|
||||
{
|
||||
/// Initializes ImGui, creates fonts, etc.
|
||||
@@ -34,5 +36,14 @@ namespace ImGuiManager
|
||||
|
||||
/// Renders any on-screen display elements.
|
||||
void RenderOSD();
|
||||
|
||||
/// Returns the scale of all on-screen elements.
|
||||
float GetGlobalScale();
|
||||
|
||||
/// Returns the standard font for external drawing.
|
||||
ImFont* GetStandardFont();
|
||||
|
||||
/// Returns the fixed-width font for external drawing.
|
||||
ImFont* GetFixedFont();
|
||||
} // namespace ImGuiManager
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ bool InputManager::SplitBinding(
|
||||
const std::string_view::size_type slash_pos = binding.find('/');
|
||||
if (slash_pos == std::string_view::npos)
|
||||
{
|
||||
Console.Warning("Malformed binding: '%*s'", static_cast<int>(binding.size()), binding.data());
|
||||
Console.Warning("Malformed binding: '%.*s'", static_cast<int>(binding.size()), binding.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -374,6 +374,128 @@ void OpenGLHostDisplay::EndPresent()
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
GL::Program::ResetLastProgram();
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
PopTimestampQuery();
|
||||
|
||||
m_gl_context->SwapBuffers();
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
KickTimestampQuery();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::CreateTimestampQueries()
|
||||
{
|
||||
const bool gles = m_gl_context->IsGLES();
|
||||
const auto GenQueries = gles ? glGenQueriesEXT : glGenQueries;
|
||||
|
||||
GenQueries(static_cast<u32>(m_timestamp_queries.size()), m_timestamp_queries.data());
|
||||
KickTimestampQuery();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::DestroyTimestampQueries()
|
||||
{
|
||||
if (m_timestamp_queries[0] == 0)
|
||||
return;
|
||||
|
||||
const bool gles = m_gl_context->IsGLES();
|
||||
const auto DeleteQueries = gles ? glDeleteQueriesEXT : glDeleteQueries;
|
||||
|
||||
if (m_timestamp_query_started)
|
||||
{
|
||||
const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
|
||||
EndQuery(m_timestamp_queries[m_write_timestamp_query]);
|
||||
}
|
||||
|
||||
DeleteQueries(static_cast<u32>(m_timestamp_queries.size()), m_timestamp_queries.data());
|
||||
m_timestamp_queries.fill(0);
|
||||
m_read_timestamp_query = 0;
|
||||
m_write_timestamp_query = 0;
|
||||
m_waiting_timestamp_queries = 0;
|
||||
m_timestamp_query_started = false;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::PopTimestampQuery()
|
||||
{
|
||||
const bool gles = m_gl_context->IsGLES();
|
||||
|
||||
if (gles)
|
||||
{
|
||||
GLint disjoint = 0;
|
||||
glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint);
|
||||
if (disjoint)
|
||||
{
|
||||
DevCon.WriteLn("GPU timing disjoint, resetting.");
|
||||
if (m_timestamp_query_started)
|
||||
glEndQueryEXT(GL_TIME_ELAPSED);
|
||||
|
||||
m_read_timestamp_query = 0;
|
||||
m_write_timestamp_query = 0;
|
||||
m_waiting_timestamp_queries = 0;
|
||||
m_timestamp_query_started = false;
|
||||
}
|
||||
}
|
||||
|
||||
while (m_waiting_timestamp_queries > 0)
|
||||
{
|
||||
const auto GetQueryObjectiv = gles ? glGetQueryObjectivEXT : glGetQueryObjectiv;
|
||||
const auto GetQueryObjectui64v = gles ? glGetQueryObjectui64vEXT : glGetQueryObjectui64v;
|
||||
|
||||
GLint available = 0;
|
||||
GetQueryObjectiv(m_timestamp_queries[m_read_timestamp_query], GL_QUERY_RESULT_AVAILABLE, &available);
|
||||
pxAssert(m_read_timestamp_query != m_write_timestamp_query);
|
||||
|
||||
if (!available)
|
||||
break;
|
||||
|
||||
u64 result = 0;
|
||||
GetQueryObjectui64v(m_timestamp_queries[m_read_timestamp_query], GL_QUERY_RESULT, &result);
|
||||
m_accumulated_gpu_time += static_cast<float>(static_cast<double>(result) / 1000000.0);
|
||||
m_read_timestamp_query = (m_read_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
|
||||
m_waiting_timestamp_queries--;
|
||||
}
|
||||
|
||||
// delay ending the current query until we've read back some
|
||||
if (m_timestamp_query_started && m_waiting_timestamp_queries < (NUM_TIMESTAMP_QUERIES - 1))
|
||||
{
|
||||
const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
|
||||
EndQuery(GL_TIME_ELAPSED);
|
||||
|
||||
m_write_timestamp_query = (m_write_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
|
||||
m_timestamp_query_started = false;
|
||||
m_waiting_timestamp_queries++;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::KickTimestampQuery()
|
||||
{
|
||||
if (m_timestamp_query_started)
|
||||
return;
|
||||
|
||||
const bool gles = m_gl_context->IsGLES();
|
||||
const auto BeginQuery = gles ? glBeginQueryEXT : glBeginQuery;
|
||||
|
||||
BeginQuery(GL_TIME_ELAPSED, m_timestamp_queries[m_write_timestamp_query]);
|
||||
m_timestamp_query_started = true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
{
|
||||
enabled &= (!m_gl_context->IsGLES() || GLAD_GL_EXT_disjoint_timer_query);
|
||||
|
||||
if (m_gpu_timing_enabled == enabled)
|
||||
return;
|
||||
|
||||
m_gpu_timing_enabled = enabled;
|
||||
if (m_gpu_timing_enabled)
|
||||
CreateTimestampQueries();
|
||||
else
|
||||
DestroyTimestampQueries();
|
||||
}
|
||||
|
||||
float OpenGLHostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
{
|
||||
const float value = m_accumulated_gpu_time;
|
||||
m_accumulated_gpu_time = 0.0f;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "HostDisplay.h"
|
||||
#include "common/GL/Context.h"
|
||||
#include "common/WindowInfo.h"
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
|
||||
class OpenGLHostDisplay final : public HostDisplay
|
||||
@@ -60,7 +62,12 @@ public:
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
||||
void SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
protected:
|
||||
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
|
||||
|
||||
const char* GetGLSLVersionString() const;
|
||||
std::string GetGLSLVersionHeader() const;
|
||||
|
||||
@@ -70,6 +77,19 @@ protected:
|
||||
|
||||
void SetSwapInterval();
|
||||
|
||||
void CreateTimestampQueries();
|
||||
void DestroyTimestampQueries();
|
||||
void PopTimestampQuery();
|
||||
void KickTimestampQuery();
|
||||
|
||||
std::unique_ptr<GL::Context> m_gl_context;
|
||||
|
||||
std::array<GLuint, NUM_TIMESTAMP_QUERIES> m_timestamp_queries = {};
|
||||
u8 m_read_timestamp_query = 0;
|
||||
u8 m_write_timestamp_query = 0;
|
||||
u8 m_waiting_timestamp_queries = 0;
|
||||
bool m_timestamp_query_started = false;
|
||||
float m_accumulated_gpu_time = 0.0f;
|
||||
bool m_gpu_timing_enabled = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -396,6 +396,16 @@ void VulkanHostDisplay::EndPresent()
|
||||
g_vulkan_context->MoveToNextCommandBuffer();
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
{
|
||||
g_vulkan_context->SetEnableGPUTiming(enabled);
|
||||
}
|
||||
|
||||
float VulkanHostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
{
|
||||
return g_vulkan_context->GetAndResetAccumulatedGPUTime();
|
||||
}
|
||||
|
||||
HostDisplay::AdapterAndModeList VulkanHostDisplay::StaticGetAdapterAndModeList(const WindowInfo* wi)
|
||||
{
|
||||
AdapterAndModeList ret;
|
||||
|
||||
@@ -51,6 +51,9 @@ public:
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
||||
void SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList(const WindowInfo* wi);
|
||||
|
||||
protected:
|
||||
|
||||
+32
-36
@@ -147,6 +147,9 @@ void GSclose()
|
||||
g_gs_device.reset();
|
||||
}
|
||||
|
||||
if (HostDisplay* display = Host::GetHostDisplay(); display)
|
||||
display->SetGPUTimingEnabled(false);
|
||||
|
||||
Host::ReleaseHostDisplay();
|
||||
}
|
||||
|
||||
@@ -238,6 +241,7 @@ static bool DoGSOpen(GSRendererType renderer, u8* basemem)
|
||||
s_gs->SetRegsMem(basemem);
|
||||
|
||||
display->SetVSync(EmuConfig.GetEffectiveVsyncMode());
|
||||
display->SetGPUTimingEnabled(GSConfig.OsdShowGPU);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -310,7 +314,6 @@ bool GSopen(const Pcsx2Config::GSOptions& config, GSRendererType renderer, u8* b
|
||||
|
||||
GSConfig = config;
|
||||
GSConfig.Renderer = renderer;
|
||||
GSConfig.MaskUserHacks();
|
||||
|
||||
if (!Host::AcquireHostDisplay(GetAPIForRenderer(renderer)))
|
||||
{
|
||||
@@ -658,21 +661,16 @@ void GSgetStats(std::string& info)
|
||||
|
||||
if (GSConfig.Renderer == GSRendererType::SW)
|
||||
{
|
||||
float sum = 0.0f;
|
||||
for (int i = GSPerfMon::WorkerDraw0; i < GSPerfMon::TimerLast; i++)
|
||||
sum += pm.GetTimer(static_cast<GSPerfMon::timer_t>(i));
|
||||
|
||||
const double fps = GetVerticalFrequency();
|
||||
const double fillrate = pm.Get(GSPerfMon::Fillrate);
|
||||
info = format("%s SW | %d S | %d P | %d D | %.2f U | %.2f D | %.2f mpps | %d%% WCPU",
|
||||
info = format("%s SW | %d S | %d P | %d D | %.2f U | %.2f D | %.2f mpps",
|
||||
api_name,
|
||||
(int)pm.Get(GSPerfMon::SyncPoint),
|
||||
(int)pm.Get(GSPerfMon::Prim),
|
||||
(int)pm.Get(GSPerfMon::Draw),
|
||||
pm.Get(GSPerfMon::Swizzle) / 1024,
|
||||
pm.Get(GSPerfMon::Unswizzle) / 1024,
|
||||
fps * fillrate / (1024 * 1024),
|
||||
static_cast<int>(std::lround(sum)));
|
||||
fps * fillrate / (1024 * 1024));
|
||||
}
|
||||
else if (GSConfig.Renderer == GSRendererType::Null)
|
||||
{
|
||||
@@ -723,7 +721,6 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||
Pcsx2Config::GSOptions old_config(std::move(GSConfig));
|
||||
GSConfig = new_config;
|
||||
GSConfig.Renderer = (GSConfig.Renderer == GSRendererType::Auto) ? GSUtil::GetPreferredRenderer() : GSConfig.Renderer;
|
||||
GSConfig.MaskUserHacks();
|
||||
if (!s_gs)
|
||||
return;
|
||||
|
||||
@@ -758,21 +755,6 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||
|
||||
// Options which aren't using the global struct yet, so we need to recreate all GS objects.
|
||||
if (
|
||||
GSConfig.ConservativeFramebuffer != old_config.ConservativeFramebuffer ||
|
||||
GSConfig.AutoFlushSW != old_config.AutoFlushSW ||
|
||||
GSConfig.PreloadFrameWithGSData != old_config.PreloadFrameWithGSData ||
|
||||
GSConfig.WrapGSMem != old_config.WrapGSMem ||
|
||||
GSConfig.Mipmap != old_config.Mipmap ||
|
||||
GSConfig.AA1 != old_config.AA1 ||
|
||||
GSConfig.UserHacks_AlignSpriteX != old_config.UserHacks_AlignSpriteX ||
|
||||
GSConfig.UserHacks_AutoFlush != old_config.UserHacks_AutoFlush ||
|
||||
GSConfig.UserHacks_CPUFBConversion != old_config.UserHacks_CPUFBConversion ||
|
||||
GSConfig.UserHacks_DisableDepthSupport != old_config.UserHacks_DisableDepthSupport ||
|
||||
GSConfig.UserHacks_DisablePartialInvalidation != old_config.UserHacks_DisablePartialInvalidation ||
|
||||
GSConfig.UserHacks_DisableSafeFeatures != old_config.UserHacks_DisableSafeFeatures ||
|
||||
GSConfig.UserHacks_MergePPSprite != old_config.UserHacks_MergePPSprite ||
|
||||
GSConfig.UserHacks_WildHack != old_config.UserHacks_WildHack ||
|
||||
GSConfig.UserHacks_TextureInsideRt != old_config.UserHacks_TextureInsideRt ||
|
||||
GSConfig.DumpGSData != old_config.DumpGSData ||
|
||||
GSConfig.SaveRT != old_config.SaveRT ||
|
||||
GSConfig.SaveFrame != old_config.SaveFrame ||
|
||||
@@ -784,12 +766,6 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||
GSConfig.SWExtraThreads != old_config.SWExtraThreads ||
|
||||
GSConfig.SWExtraThreadsHeight != old_config.SWExtraThreadsHeight ||
|
||||
|
||||
GSConfig.UserHacks_HalfBottomOverride != old_config.UserHacks_HalfBottomOverride ||
|
||||
GSConfig.UserHacks_HalfPixelOffset != old_config.UserHacks_HalfPixelOffset ||
|
||||
GSConfig.UserHacks_RoundSprite != old_config.UserHacks_RoundSprite ||
|
||||
GSConfig.UserHacks_TCOffsetX != old_config.UserHacks_TCOffsetX ||
|
||||
GSConfig.UserHacks_TCOffsetY != old_config.UserHacks_TCOffsetY ||
|
||||
|
||||
GSConfig.ShadeBoost_Brightness != old_config.ShadeBoost_Brightness ||
|
||||
GSConfig.ShadeBoost_Contrast != old_config.ShadeBoost_Contrast ||
|
||||
GSConfig.ShadeBoost_Saturation != old_config.ShadeBoost_Saturation ||
|
||||
@@ -806,17 +782,29 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||
// This is where we would do finer-grained checks in the future.
|
||||
// For example, flushing the texture cache when mipmap settings change.
|
||||
|
||||
if (GSConfig.HWMipmap != old_config.HWMipmap || GSConfig.CRCHack != old_config.CRCHack)
|
||||
if (GSConfig.CRCHack != old_config.CRCHack ||
|
||||
GSConfig.PointListPalette != old_config.PointListPalette)
|
||||
{
|
||||
// for automatic mipmaps, we need to reload the crc
|
||||
s_gs->SetGameCRC(s_gs->GetGameCRC(), s_gs->GetGameCRCOptions());
|
||||
}
|
||||
|
||||
// reload texture cache when trilinear filtering or mipmap options change
|
||||
if (GSConfig.HWMipmap != old_config.HWMipmap ||
|
||||
// renderer-specific options (e.g. auto flush, TC offset)
|
||||
s_gs->UpdateSettings(old_config);
|
||||
|
||||
// reload texture cache when trilinear filtering or TC options change
|
||||
if (
|
||||
(GSConfig.UseHardwareRenderer() && GSConfig.HWMipmap != old_config.HWMipmap) ||
|
||||
GSConfig.ConservativeFramebuffer != old_config.ConservativeFramebuffer ||
|
||||
GSConfig.TexturePreloading != old_config.TexturePreloading ||
|
||||
GSConfig.UserHacks_TriFilter != old_config.UserHacks_TriFilter ||
|
||||
GSConfig.GPUPaletteConversion != old_config.GPUPaletteConversion)
|
||||
GSConfig.GPUPaletteConversion != old_config.GPUPaletteConversion ||
|
||||
GSConfig.PreloadFrameWithGSData != old_config.PreloadFrameWithGSData ||
|
||||
GSConfig.WrapGSMem != old_config.WrapGSMem ||
|
||||
GSConfig.UserHacks_CPUFBConversion != old_config.UserHacks_CPUFBConversion ||
|
||||
GSConfig.UserHacks_DisableDepthSupport != old_config.UserHacks_DisableDepthSupport ||
|
||||
GSConfig.UserHacks_DisablePartialInvalidation != old_config.UserHacks_DisablePartialInvalidation ||
|
||||
GSConfig.UserHacks_TextureInsideRt != old_config.UserHacks_TextureInsideRt)
|
||||
{
|
||||
s_gs->PurgeTextureCache();
|
||||
s_gs->PurgePool();
|
||||
@@ -836,6 +824,12 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||
{
|
||||
s_gs->PurgeTextureCache();
|
||||
}
|
||||
|
||||
if (GSConfig.OsdShowGPU != old_config.OsdShowGPU)
|
||||
{
|
||||
if (HostDisplay* display = Host::GetHostDisplay(); display)
|
||||
display->SetGPUTimingEnabled(GSConfig.OsdShowGPU);
|
||||
}
|
||||
}
|
||||
|
||||
void GSSwitchRenderer(GSRendererType new_renderer)
|
||||
@@ -1341,6 +1335,7 @@ void GSApp::Init()
|
||||
m_default_configuration["OsdShowSpeed"] = "0";
|
||||
m_default_configuration["OsdShowFPS"] = "0";
|
||||
m_default_configuration["OsdShowCPU"] = "0";
|
||||
m_default_configuration["OsdShowGPU"] = "0";
|
||||
m_default_configuration["OsdShowResolution"] = "0";
|
||||
m_default_configuration["OsdShowGSStats"] = "0";
|
||||
m_default_configuration["OsdShowIndicators"] = "1";
|
||||
@@ -1358,6 +1353,7 @@ void GSApp::Init()
|
||||
m_default_configuration["override_GL_ARB_texture_barrier"] = "-1";
|
||||
m_default_configuration["paltex"] = "0";
|
||||
m_default_configuration["png_compression_level"] = std::to_string(Z_BEST_SPEED);
|
||||
m_default_configuration["PointListPalette"] = "0";
|
||||
m_default_configuration["PrecacheTextureReplacements"] = "0";
|
||||
m_default_configuration["preload_frame_with_gs_data"] = "0";
|
||||
m_default_configuration["Renderer"] = std::to_string(static_cast<int>(GSRendererType::Auto));
|
||||
@@ -1395,8 +1391,8 @@ void GSApp::Init()
|
||||
m_default_configuration["UserHacks_HalfPixelOffset"] = "0";
|
||||
m_default_configuration["UserHacks_merge_pp_sprite"] = "0";
|
||||
m_default_configuration["UserHacks_round_sprite_offset"] = "0";
|
||||
m_default_configuration["UserHacks_SkipDraw"] = "0";
|
||||
m_default_configuration["UserHacks_SkipDraw_Offset"] = "0";
|
||||
m_default_configuration["UserHacks_SkipDraw_Start"] = "0";
|
||||
m_default_configuration["UserHacks_SkipDraw_End"] = "0";
|
||||
m_default_configuration["UserHacks_TCOffsetX"] = "0";
|
||||
m_default_configuration["UserHacks_TCOffsetY"] = "0";
|
||||
m_default_configuration["UserHacks_TextureInsideRt"] = "0";
|
||||
|
||||
@@ -538,7 +538,7 @@ bool GSCapture::BeginCapture(float fps, GSVector2i recommendedResolution, float
|
||||
|
||||
for (int i = 0; i < m_threads; i++)
|
||||
{
|
||||
m_workers.push_back(std::unique_ptr<GSPng::Worker>(new GSPng::Worker(&GSPng::Process)));
|
||||
m_workers.push_back(std::unique_ptr<GSPng::Worker>(new GSPng::Worker({}, &GSPng::Process, {})));
|
||||
}
|
||||
|
||||
m_capturing = true;
|
||||
|
||||
+33
-185
@@ -26,14 +26,7 @@ const CRC::Game CRC::m_games[] =
|
||||
{0x68CE6801, ArTonelico2, JP, 0},
|
||||
{0xCE2C1DBF, ArTonelico2, EU, 0},
|
||||
{0x2113EA2E, MetalSlug6, JP, 0},
|
||||
{0x42E05BAF, TomoyoAfter, JP, PointListPalette},
|
||||
{0x7800DC84, Clannad, JP, PointListPalette},
|
||||
{0xA6167B59, Lamune, JP, PointListPalette},
|
||||
{0xDDB59F46, KyuuketsuKitanMoonties, JP, PointListPalette},
|
||||
{0xC8EE2562, PiaCarroteYoukosoGPGakuenPrincess, JP, PointListPalette},
|
||||
{0x6CF94A43, KazokuKeikakuKokoroNoKizuna, JP, PointListPalette},
|
||||
{0xEDAF602D, DuelSaviorDestiny, JP, PointListPalette},
|
||||
{0xBB63D785, OneTwentyYenStories, JP, PointListPalette}, // no Haru: 120 Yen Stories
|
||||
{0xA6167B59, Lamune, JP, 0},
|
||||
{0xA39517AB, FFX, EU, 0},
|
||||
{0x78D83FD5, FFX, EU, 0}, // Demo
|
||||
{0xA39517AE, FFX, FR, 0},
|
||||
@@ -94,12 +87,6 @@ const CRC::Game CRC::m_games[] =
|
||||
{0x71521863, SFEX3, US, 0},
|
||||
{0x63642E9F, SFEX3, JP, 0},
|
||||
{0xCA1F6E53, SFEX3, JP, 0}, // Taikenban Disc (Demo/Trial)
|
||||
{0xC19A374E, SoTC, US, 0},
|
||||
{0x7D8F539A, SoTC, EU, 0},
|
||||
{0x0F0C4A9C, SoTC, EU, 0},
|
||||
{0x877F3436, SoTC, JP, 0},
|
||||
{0xA17D6AAA, SoTC, KO, 0},
|
||||
{0x877B3D35, SoTC, CH, 0},
|
||||
{0x6F8545DB, ICO, US, 0},
|
||||
{0x48CDF317, ICO, US, 0}, // Demo
|
||||
{0xB01A4C95, ICO, JP, 0},
|
||||
@@ -163,9 +150,6 @@ const CRC::Game CRC::m_games[] =
|
||||
{0xA32F7CD0, AceCombat4, US, 0}, // Also needed for automatic mipmapping
|
||||
{0x5ED8FB53, AceCombat4, JP, 0},
|
||||
{0x1B9B7563, AceCombat4, EU, 0},
|
||||
{0x39B574F0, AceCombat5, US, 0}, // The Unsung War
|
||||
{0x86089F31, AceCombat5, JP, 0},
|
||||
{0x1D54FEA9, AceCombat5, EU, 0}, // Squadron Leader
|
||||
{0xFC46EA61, Tekken5, JP, 0},
|
||||
{0x1F88EE37, Tekken5, EU, 0},
|
||||
{0x1F88BECD, Tekken5, EU, 0}, // language selector...
|
||||
@@ -206,7 +190,6 @@ const CRC::Game CRC::m_games[] =
|
||||
{0xA3643EB1, GiTS, KO, 0},
|
||||
{0x28557423, GiTS, RU, 0},
|
||||
{0xBF6F101F, GiTS, EU, 0}, // same CRC as another US disc
|
||||
{0xF442260C, MajokkoALaMode2, JP, PointListPalette},
|
||||
{0xA616A6C2, TalesOfAbyss, US, 0},
|
||||
{0x14FE77F7, TalesOfAbyss, US, 0},
|
||||
{0xAA5EC3A3, TalesOfAbyss, JP, 0},
|
||||
@@ -243,10 +226,10 @@ const CRC::Game CRC::m_games[] =
|
||||
{0xC5B75C7C, Oneechanbara2Special, JP, 0},
|
||||
{0xC725CC6C, Oneechanbara2Special, JP, 0},
|
||||
{0x07608CA2, Oneechanbara2Special, EU, 0}, // Zombie Hunters 2
|
||||
{0xE0347841, XenosagaE3, JP, TextureInsideRt},
|
||||
{0xA707236E, XenosagaE3, JP, TextureInsideRt}, // Demo
|
||||
{0xA4E88698, XenosagaE3, CH, TextureInsideRt},
|
||||
{0x2088950A, XenosagaE3, US, TextureInsideRt},
|
||||
{0xE0347841, XenosagaE3, JP, 0},
|
||||
{0xA707236E, XenosagaE3, JP, 0}, // Demo
|
||||
{0xA4E88698, XenosagaE3, CH, 0},
|
||||
{0x2088950A, XenosagaE3, US, 0},
|
||||
{0xB1995E29, ShadowofRome, EU, 0},
|
||||
{0x958DCA28, ShadowofRome, EU, 0},
|
||||
{0x57818AF6, ShadowofRome, US, 0},
|
||||
@@ -315,14 +298,14 @@ const CRC::Game CRC::m_games[] =
|
||||
{0x812C5A96, ShinOnimusha, EU, 0},
|
||||
{0xFE44479E, ShinOnimusha, US, 0},
|
||||
{0xFFDE85E9, ShinOnimusha, US, 0},
|
||||
{0xE21404E2, GetawayGames, US, TextureInsideRt}, // Getaway
|
||||
{0xE8249852, GetawayGames, JP, TextureInsideRt}, // Getaway
|
||||
{0x458485EF, GetawayGames, EU, TextureInsideRt}, // Getaway
|
||||
{0x5DFBE144, GetawayGames, EU, TextureInsideRt}, // Getaway
|
||||
{0xE78971DF, GetawayGames, US, TextureInsideRt}, // GetawayBlackMonday
|
||||
{0x342D97FA, GetawayGames, US, TextureInsideRt}, // GetawayBlackMonday Demo
|
||||
{0xE8C0AD1A, GetawayGames, JP, TextureInsideRt}, // GetawayBlackMonday
|
||||
{0x09C3DF79, GetawayGames, EU, TextureInsideRt}, // GetawayBlackMonday
|
||||
{0xE21404E2, GetawayGames, US, 0}, // Getaway
|
||||
{0xE8249852, GetawayGames, JP, 0}, // Getaway
|
||||
{0x458485EF, GetawayGames, EU, 0}, // Getaway
|
||||
{0x5DFBE144, GetawayGames, EU, 0}, // Getaway
|
||||
{0xE78971DF, GetawayGames, US, 0}, // GetawayBlackMonday
|
||||
{0x342D97FA, GetawayGames, US, 0}, // GetawayBlackMonday Demo
|
||||
{0xE8C0AD1A, GetawayGames, JP, 0}, // GetawayBlackMonday
|
||||
{0x09C3DF79, GetawayGames, EU, 0}, // GetawayBlackMonday
|
||||
{0x1130BF23, SakuraTaisen, CH, 0},
|
||||
{0x4FAE8B83, SakuraTaisen, KO, 0},
|
||||
{0xEF06DBD6, SakuraWarsSoLongMyLove, JP, 0},
|
||||
@@ -350,161 +333,26 @@ const CRC::Game CRC::m_games[] =
|
||||
{0XE1BF5DCA, SuperManReturns, US, 0},
|
||||
{0XE8F7BAB6, SuperManReturns, EU, 0},
|
||||
{0x06A7506A, SacredBlaze, JP, 0},
|
||||
{0x9C712FF0, Jak1, EU, TextureInsideRt}, // Jak and Daxter: The Precursor Legacy
|
||||
{0x1B3976AB, Jak1, US, TextureInsideRt},
|
||||
{0x472E7699, Jak1, US, TextureInsideRt}, // Greatest Hits
|
||||
{0x96A608C5, Jak1, US, TextureInsideRt}, // Cingular Wireless Demo, PS Underground Demo
|
||||
{0xEDE4FE64, Jak1, JP, TextureInsideRt}, // Jak x Daxter: Kyuusekai no Isan
|
||||
{0x2A7FD3B4, Jak1, JP, TextureInsideRt}, // Demo
|
||||
{0x2479F4A9, Jak2, EU, TextureInsideRt},
|
||||
{0xF41C1B29, Jak2, EU, TextureInsideRt}, // Demo
|
||||
{0x9184AAF1, Jak2, US, TextureInsideRt},
|
||||
{0xA2034C69, Jak2, US, TextureInsideRt}, // Demo
|
||||
{0x25FE4D23, Jak2, KO, TextureInsideRt},
|
||||
{0xB4976DAF, Jak2, JP, TextureInsideRt}, // Jak II: Jak x Daxter 2
|
||||
{0x43D4FF3E, Jak2, JP, TextureInsideRt}, // Demo
|
||||
{0x12804727, Jak3, EU, TextureInsideRt},
|
||||
{0xE59E10BF, Jak3, EU, TextureInsideRt},
|
||||
{0xCA68E4D5, Jak3, EU, TextureInsideRt}, // Demo
|
||||
{0x644CFD03, Jak3, US, TextureInsideRt},
|
||||
{0xD401BC20, Jak3, US, TextureInsideRt}, // Demo
|
||||
{0xD1368EAE, Jak3, KO, TextureInsideRt},
|
||||
{0xDF659E77, JakX, EU, TextureInsideRt}, // Jak X: Combat Racing
|
||||
{0xC20596DB, JakX, EU, TextureInsideRt}, // Beta Trial Disc, v0.01
|
||||
{0x3091E6FB, JakX, US, TextureInsideRt},
|
||||
{0xC417D919, JakX, US, TextureInsideRt}, // Demo
|
||||
{0xDA366A53, JakX, US, TextureInsideRt}, // Public Beta v.1
|
||||
{0x7B564230, JakX, US, TextureInsideRt}, // Jak and Daxter Complete Trilogy Demo
|
||||
{0xDBA28C59, JakX, US, TextureInsideRt}, // Greatest Hits
|
||||
{0x4653CA3E, HarleyDavidson, US, 0},
|
||||
// Games list for Automatic Mipmapping
|
||||
// Basic mipmapping
|
||||
{0x194C9F38, AceCombatZero, EU, 0}, // Ace Combat: The Belkan War
|
||||
{0x65729657, AceCombatZero, US, 0},
|
||||
{0xA04B52DB, AceCombatZero, JP, 0},
|
||||
{0x2799A4E5, AceCombatZero, KO, 0},
|
||||
{0x09B3AD4D, ApeEscape2, EU, 0},
|
||||
{0xADCDCB88, ApeEscape2, EU, 0}, // Spanish version
|
||||
{0xBBB21612, ApeEscape2, DE, 0},
|
||||
{0xE2B8D3B2, ApeEscape2, IT, 0},
|
||||
{0x8B6FE2EA, ApeEscape2, FR, 0},
|
||||
{0xBDD9F5E1, ApeEscape2, US, 0},
|
||||
{0xFE0A6AB6, ApeEscape2, JP, 0}, // Saru! Get You! 2
|
||||
{0x64A9982B, ApeEscape2, CH, 0},
|
||||
{0xEC8EF2DE, Barnyard, US, 0}, // Nickelodeon: Barnyard
|
||||
{0x0B2F3DEE, Barnyard, KO, 0},
|
||||
{0x5267A845, Barnyard, EU, 0},
|
||||
{0x0940508D, BrianLaraInternationalCricket, EU, 0},
|
||||
{0x0BAA8DD8, DarkCloud, EU, 0},
|
||||
{0x1DF41F33, DarkCloud, US, 0},
|
||||
{0xA5C05C78, DarkCloud, US, 0},
|
||||
{0x60AA5049, DarkCloud, KO, 0},
|
||||
{0xECD8E386, DarkCloud, JP, 0},
|
||||
{0x67A29886, DestroyAllHumans, US, 0},
|
||||
{0xE3E8E893, DestroyAllHumans, EU, 0},
|
||||
{0x42DF8C8C, DestroyAllHumans2, US, 0},
|
||||
{0x743E10C2, DestroyAllHumans2, EU, 0},
|
||||
{0x67C38BAA, FIFA03, US, 0},
|
||||
{0x722BBD62, FIFA03, EU, 0},
|
||||
{0x2BCCF704, FIFA03, EU, 0},
|
||||
{0xCC6AA742, FIFA04, KO, 0},
|
||||
{0x2C6A4E2E, FIFA04, US, 0},
|
||||
{0x684ADFC6, FIFA04, EU, 0},
|
||||
{0x972611BB, FIFA05, US, 0},
|
||||
{0x972719A3, FIFA05, EU, 0},
|
||||
{0xC5473413, HarryPotterATCOS, NoRegion, 0}, // EU and US versions have the same CRC - Chamber Of Secrets
|
||||
{0xE1963055, HarryPotterATCOS, JP, 0}, // Harry Potter to Himitsu no Heya
|
||||
{0xE90BE9F8, HarryPotterATCOS, JP, 0}, // Coca Cola original Version
|
||||
{0xB38CC628, HarryPotterATGOF, US, 0},
|
||||
{0xCDE017A7, HarryPotterATGOF, KO, 0},
|
||||
{0xB18DC525, HarryPotterATGOF, EU, 0},
|
||||
{0x9C3A84F4, HarryPotterATHBP, US, 0}, // Half-Blood Prince
|
||||
{0xCB598BC2, HarryPotterATHBP, EU, 0},
|
||||
{0x51E019BC, HarryPotterATPOA, NoRegion, 0}, // EU and US versions have the same CRC - Prisoner of Azkaban
|
||||
{0x99A8B4FF, HarryPotterATPOA, KO, 0},
|
||||
{0xA8901AD6, HarryPotterATPOA, JP, 0}, // Harry Potter to Azkaban no Shuujin
|
||||
{0x51E417AA, HarryPotterATPOA, EU, 0},
|
||||
{0x4C01B1B0, HarryPotterOOTP, US, 0}, // Order Of The Phoenix
|
||||
{0x01A9BF0E, HarryPotterOOTP, EU, 0},
|
||||
{0x960FFA6A, JurassicPark, EU, 0},
|
||||
{0xA99B8FE7, JurassicPark, US, 0},
|
||||
{0x230CB71D, SoulReaver2, US, 0},
|
||||
{0x1771BFE4, SoulReaver2, US, 0},
|
||||
{0x6F991F52, SoulReaver2, JP, 0},
|
||||
{0x1B7FF35A, SoulReaver2, KO, 0},
|
||||
{0x6D8B4CD1, SoulReaver2, EU, 0},
|
||||
{0x728AB07C, LegacyOfKainDefiance, US, 0},
|
||||
{0xBCAD1E8A, LegacyOfKainDefiance, EU, 0},
|
||||
{0x28D09BF9, NicktoonsUnite, US, 0},
|
||||
{0xF25266C4, NicktoonsUnite, EU, 0}, // Nickelodeon SpongeBob SquarePants And Friends Unite
|
||||
{0x7AE1C04B, Persona3, US, 0}, // Regular Version
|
||||
{0x05C3D28F, Persona3, JP, 0},
|
||||
{0xBCD68B1E, Persona3, KO, 0},
|
||||
{0x8A557EE5, Persona3, EU, 0},
|
||||
{0x94A82AAA, Persona3, US, 0}, // FES
|
||||
{0x232C7D72, Persona3, JP, 0},
|
||||
{0x8897C208, Persona3, KO, 0},
|
||||
{0xF64A6AE5, Persona3, EU, 0},
|
||||
{0x2BDA8ADB, ProjectSnowblind, US, 0},
|
||||
{0xF00CA82B, ProjectSnowblind, EU, 0},
|
||||
{0xF1583665, ProjectSnowblind, EU, 0},
|
||||
{0xA56A0525, Quake3Revolution, US, 0},
|
||||
{0x2064ACE6, Quake3Revolution, EU, 0},
|
||||
{0xCE4933D0, RatchetAndClank, US, 0},
|
||||
{0x6F191506, RatchetAndClank, US, 0}, // E3 Demo
|
||||
{0x81CBFEA2, RatchetAndClank, US, 0}, // EB Games Demo
|
||||
{0x56A35F77, RatchetAndClank, JP, 0},
|
||||
{0x76F724A3, RatchetAndClank, EU, 0},
|
||||
{0x6A8F18B9, RatchetAndClank, EU, 0},
|
||||
{0x5C19F3B7, RatchetAndClank, EU, 0}, // Regular Demo
|
||||
{0xB3A71D10, RatchetAndClank2, US, 0}, // Going Commando
|
||||
{0x38996035, RatchetAndClank2, US, 0},
|
||||
{0xF700EE7E, RatchetAndClank2, US, 0}, // Regular Demo
|
||||
{0xF67ADF58, RatchetAndClank2, US, 0}, // Retail Employees Demo
|
||||
{0xDF6F94A1, RatchetAndClank2, US, 0}, // Demo - Going Commando & Jak II
|
||||
{0x89A26EC9, RatchetAndClank2, KO, 0},
|
||||
{0x8CAA5F16, RatchetAndClank2, JP, 0}, // Gagaga! Ginga no Commando-ssu
|
||||
{0x2F486E6F, RatchetAndClank2, EU, 0},
|
||||
{0x45FE0CC4, RatchetAndClank3, US, 0}, // Up Your Arsenal
|
||||
{0x2A12175A, RatchetAndClank3, US, 0}, // Regular Demo
|
||||
{0xCC53C3B4, RatchetAndClank3, US, 0}, // Public Beta v1.0
|
||||
{0x9FCC4BA4, RatchetAndClank3, KO, 0},
|
||||
{0x64DC6000, RatchetAndClank3, JP, 0}, // Totsugeki! Galactic Rangers
|
||||
{0x17125698, RatchetAndClank3, EU, 0},
|
||||
{0x4A85FC67, RatchetAndClank3, EU, 0}, // Beta Trial Disc
|
||||
{0x9BFBCD42, RatchetAndClank4, US, 0}, // Deadlocked
|
||||
{0xD301186D, RatchetAndClank4, US, 0}, // Regular Demo
|
||||
{0xBDF8A887, RatchetAndClank4, US, 0}, // Public Beta v.1
|
||||
{0x529BC7CC, RatchetAndClank4, KO, 0},
|
||||
{0x2EC9DA96, RatchetAndClank4, JP, 0}, // GiriGiri Ginga no Giga Battle
|
||||
{0x76975025, RatchetAndClank4, JP, 0}, // Regular Demo
|
||||
{0xD697D204, RatchetAndClank4, EU, 0}, // Ratchet Gladiator
|
||||
{0x8661F7BA, RatchetAndClank5, US, 0}, // Size Matters
|
||||
{0x7029DCE6, RatchetAndClank5, KO, 0},
|
||||
{0x9ADCF7AF, RatchetAndClank5, JP, 0}, // Gekitotsu! Dodeka Ginga no Miri Miri Gundan
|
||||
{0xFCB981D5, RatchetAndClank5, EU, 0},
|
||||
{0x8634861F, RickyPontingInternationalCricket, EU, 0},
|
||||
{0xDDAC3815, Shox, US, 0},
|
||||
{0xF84FE9DE, Shox, KO, 0},
|
||||
{0x09F4038B, Shox, EU, 0},
|
||||
{0x78FFA39F, Shox, EU, 0},
|
||||
{0x3DF10389, Shox, EU, 0},
|
||||
{0x43CC009B, SlamTennis, EU, 0},
|
||||
{0xF17AF8BD, TheIncredibleHulkUD, US, 0},
|
||||
{0xEA8D4BDF, TheIncredibleHulkUD, US, 0},
|
||||
{0x6B3D50A5, TheIncredibleHulkUD, EU, 0},
|
||||
{0x2B58234D, TribesAerialAssault, US, 0},
|
||||
{0x4D22DB95, Whiplash, US, 0},
|
||||
{0xE8A97250, Whiplash, EU, 0},
|
||||
{0xB1BE3E51, Whiplash, EU, 0},
|
||||
{0x4C33FA2A, IndianaJonesAndTheEmperorsTomb, US, TextureInsideRt}, // TODO Add more CRCs (https://pcsx2.net/compatibility-list.html).
|
||||
{0xAE0E098F, IndianaJonesAndTheEmperorsTomb, DE, TextureInsideRt},
|
||||
{0xBBC3EFFA, WildArms4, US, TextureInsideRt}, // TODO Add more CRCs (https://pcsx2.net/compatibility-list.html).
|
||||
{0x36802E57, BeyondGoodAndEvil, US, TextureInsideRt}, // TODO Add more CRCs (https://pcsx2.net/compatibility-list.html).
|
||||
{0x08FFF00D, SSX3, US, TextureInsideRt},
|
||||
{0xCE942B2A, SSX3, EU, TextureInsideRt}, // TODO Add more CRCs (https://pcsx2.net/compatibility-list.html).
|
||||
{0x1FCC0CFB, DrivingEmotionTypeS, US, TextureInsideRt},
|
||||
{0x034836F8, DrivingEmotionTypeS, JP, TextureInsideRt}, // TODO Add more CRCs (https://pcsx2.net/compatibility-list.html).
|
||||
{0x2479F4A9, Jak2, EU, 0},
|
||||
{0xF41C1B29, Jak2, EU, 0}, // Demo
|
||||
{0x9184AAF1, Jak2, US, 0},
|
||||
{0xA2034C69, Jak2, US, 0}, // Demo
|
||||
{0x25FE4D23, Jak2, KO, 0},
|
||||
{0xB4976DAF, Jak2, JP, 0}, // Jak II: Jak x Daxter 2
|
||||
{0x43D4FF3E, Jak2, JP, 0}, // Demo
|
||||
{0x12804727, Jak3, EU, 0},
|
||||
{0xE59E10BF, Jak3, EU, 0},
|
||||
{0xCA68E4D5, Jak3, EU, 0}, // Demo
|
||||
{0x644CFD03, Jak3, US, 0},
|
||||
{0xD401BC20, Jak3, US, 0}, // Demo
|
||||
{0xD1368EAE, Jak3, KO, 0},
|
||||
{0xDF659E77, JakX, EU, 0}, // Jak X: Combat Racing
|
||||
{0xC20596DB, JakX, EU, 0}, // Beta Trial Disc, v0.01
|
||||
{0x3091E6FB, JakX, US, 0},
|
||||
{0xC417D919, JakX, US, 0}, // Demo
|
||||
{0xDA366A53, JakX, US, 0}, // Public Beta v.1
|
||||
{0x7B564230, JakX, US, 0}, // Jak and Daxter Complete Trilogy Demo
|
||||
{0xDBA28C59, JakX, US, 0}, // Greatest Hits
|
||||
};
|
||||
|
||||
std::map<u32, const CRC::Game*> CRC::m_map;
|
||||
|
||||
@@ -23,116 +23,65 @@ public:
|
||||
enum Title
|
||||
{
|
||||
NoTitle,
|
||||
AceCombatZero,
|
||||
AceCombat4,
|
||||
AceCombat5,
|
||||
ApeEscape2,
|
||||
ArTonelico2,
|
||||
Barnyard,
|
||||
BeyondGoodAndEvil,
|
||||
BigMuthaTruckers,
|
||||
BrianLaraInternationalCricket,
|
||||
BurnoutGames,
|
||||
Clannad,
|
||||
CrashBandicootWoC,
|
||||
DarkCloud,
|
||||
DBZBT2,
|
||||
DBZBT3,
|
||||
DeathByDegreesTekkenNinaWilliams,
|
||||
DestroyAllHumans,
|
||||
DestroyAllHumans2,
|
||||
DrivingEmotionTypeS,
|
||||
DuelSaviorDestiny,
|
||||
EvangelionJo,
|
||||
FFX,
|
||||
FFX2,
|
||||
FFXII,
|
||||
FIFA03,
|
||||
FIFA04,
|
||||
FIFA05,
|
||||
FightingBeautyWulong,
|
||||
GetawayGames,
|
||||
GiTS,
|
||||
GodHand,
|
||||
GodOfWar,
|
||||
GodOfWar2,
|
||||
HarleyDavidson,
|
||||
HarryPotterATCOS,
|
||||
HarryPotterATGOF,
|
||||
HarryPotterATHBP,
|
||||
HarryPotterATPOA,
|
||||
HarryPotterOOTP,
|
||||
HauntingGround,
|
||||
ICO,
|
||||
IkkiTousen,
|
||||
IndianaJonesAndTheEmperorsTomb,
|
||||
Jak1,
|
||||
Jak2,
|
||||
Jak3,
|
||||
JakX,
|
||||
JurassicPark,
|
||||
KazokuKeikakuKokoroNoKizuna,
|
||||
KnightsOfTheTemple2,
|
||||
Kunoichi,
|
||||
KyuuketsuKitanMoonties,
|
||||
Lamune,
|
||||
LegacyOfKainDefiance,
|
||||
MajokkoALaMode2,
|
||||
Manhunt2,
|
||||
MetalSlug6,
|
||||
MidnightClub3,
|
||||
NicktoonsUnite,
|
||||
Okami,
|
||||
Oneechanbara2Special,
|
||||
OneTwentyYenStories,
|
||||
Persona3,
|
||||
PiaCarroteYoukosoGPGakuenPrincess,
|
||||
PolyphonyDigitalGames,
|
||||
ProjectSnowblind,
|
||||
Quake3Revolution,
|
||||
RatchetAndClank,
|
||||
RatchetAndClank2,
|
||||
RatchetAndClank3,
|
||||
RatchetAndClank4,
|
||||
RatchetAndClank5,
|
||||
RedDeadRevolver,
|
||||
RickyPontingInternationalCricket,
|
||||
RozenMaidenGebetGarden,
|
||||
SacredBlaze,
|
||||
SakuraTaisen,
|
||||
SakuraWarsSoLongMyLove,
|
||||
SFEX3,
|
||||
ShadowHearts,
|
||||
ShadowofRome,
|
||||
ShinOnimusha,
|
||||
Shox,
|
||||
Simple2000Vol114,
|
||||
SkyGunner,
|
||||
SlamTennis,
|
||||
SMTNocturne,
|
||||
SonicUnleashed,
|
||||
SoTC,
|
||||
SoulReaver2,
|
||||
Spartan,
|
||||
SteambotChronicles,
|
||||
SSX3,
|
||||
SuperManReturns,
|
||||
SVCChaos,
|
||||
TalesOfAbyss,
|
||||
TalesOfLegendia,
|
||||
TalesofSymphonia,
|
||||
Tekken5,
|
||||
TheIncredibleHulkUD,
|
||||
TombRaiderAnniversary,
|
||||
TombRaiderLegend,
|
||||
TombRaiderUnderworld,
|
||||
TriAceGames,
|
||||
TribesAerialAssault,
|
||||
TomoyoAfter,
|
||||
UltramanFightingEvolution,
|
||||
UrbanReign,
|
||||
Whiplash,
|
||||
WildArms4,
|
||||
XenosagaE3,
|
||||
YakuzaGames,
|
||||
ZettaiZetsumeiToshi2,
|
||||
@@ -156,12 +105,6 @@ public:
|
||||
RegionCount,
|
||||
};
|
||||
|
||||
enum Flags
|
||||
{
|
||||
PointListPalette = 1,
|
||||
TextureInsideRt = 2,
|
||||
};
|
||||
|
||||
struct Game
|
||||
{
|
||||
u32 crc;
|
||||
|
||||
+42
-9
@@ -16,6 +16,7 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSDump.h"
|
||||
#include "GSExtra.h"
|
||||
#include "GSState.h"
|
||||
|
||||
GSDumpBase::GSDumpBase(const std::string& fn)
|
||||
: m_frames(0)
|
||||
@@ -32,10 +33,38 @@ GSDumpBase::~GSDumpBase()
|
||||
fclose(m_gs);
|
||||
}
|
||||
|
||||
void GSDumpBase::AddHeader(u32 crc, const freezeData& fd, const GSPrivRegSet* regs)
|
||||
void GSDumpBase::AddHeader(const std::string& serial, u32 crc,
|
||||
u32 screenshot_width, u32 screenshot_height, const u32* screenshot_pixels,
|
||||
const freezeData& fd, const GSPrivRegSet* regs)
|
||||
{
|
||||
AppendRawData(&crc, 4);
|
||||
AppendRawData(&fd.size, 4);
|
||||
// New header: CRC of FFFFFFFF, secondary header, full header follows.
|
||||
const u32 fake_crc = 0xFFFFFFFFu;
|
||||
AppendRawData(&fake_crc, 4);
|
||||
|
||||
// Compute full header size (with serial).
|
||||
// This acts as the state size for loading older dumps.
|
||||
const u32 screenshot_size = screenshot_width * screenshot_height * sizeof(screenshot_pixels[0]);
|
||||
const u32 header_size = sizeof(GSDumpHeader) + static_cast<u32>(serial.size()) + screenshot_size;
|
||||
AppendRawData(&header_size, 4);
|
||||
|
||||
// Write hader.
|
||||
GSDumpHeader header = {};
|
||||
header.state_version = GSState::STATE_VERSION;
|
||||
header.state_size = fd.size;
|
||||
header.crc = crc;
|
||||
header.serial_offset = sizeof(header);
|
||||
header.serial_size = static_cast<u32>(serial.size());
|
||||
header.screenshot_width = screenshot_width;
|
||||
header.screenshot_height = screenshot_height;
|
||||
header.screenshot_offset = header.serial_offset + header.serial_size;
|
||||
header.screenshot_size = screenshot_size;
|
||||
AppendRawData(&header, sizeof(header));
|
||||
if (!serial.empty())
|
||||
AppendRawData(serial.data(), serial.size());
|
||||
if (screenshot_pixels)
|
||||
AppendRawData(screenshot_pixels, screenshot_size);
|
||||
|
||||
// Then the real state data.
|
||||
AppendRawData(fd.data, fd.size);
|
||||
AppendRawData(regs, sizeof(*regs));
|
||||
}
|
||||
@@ -92,18 +121,20 @@ void GSDumpBase::Write(const void* data, size_t size)
|
||||
// GSDump implementation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
GSDump::GSDump(const std::string& fn, u32 crc, const freezeData& fd, const GSPrivRegSet* regs)
|
||||
GSDumpUncompressed::GSDumpUncompressed(const std::string& fn, const std::string& serial, u32 crc,
|
||||
u32 screenshot_width, u32 screenshot_height, const u32* screenshot_pixels,
|
||||
const freezeData& fd, const GSPrivRegSet* regs)
|
||||
: GSDumpBase(fn + ".gs")
|
||||
{
|
||||
AddHeader(crc, fd, regs);
|
||||
AddHeader(serial, crc, screenshot_width, screenshot_height, screenshot_pixels, fd, regs);
|
||||
}
|
||||
|
||||
void GSDump::AppendRawData(const void* data, size_t size)
|
||||
void GSDumpUncompressed::AppendRawData(const void* data, size_t size)
|
||||
{
|
||||
Write(data, size);
|
||||
}
|
||||
|
||||
void GSDump::AppendRawData(u8 c)
|
||||
void GSDumpUncompressed::AppendRawData(u8 c)
|
||||
{
|
||||
Write(&c, 1);
|
||||
}
|
||||
@@ -112,7 +143,9 @@ void GSDump::AppendRawData(u8 c)
|
||||
// GSDumpXz implementation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
GSDumpXz::GSDumpXz(const std::string& fn, u32 crc, const freezeData& fd, const GSPrivRegSet* regs)
|
||||
GSDumpXz::GSDumpXz(const std::string& fn, const std::string& serial, u32 crc,
|
||||
u32 screenshot_width, u32 screenshot_height, const u32* screenshot_pixels,
|
||||
const freezeData& fd, const GSPrivRegSet* regs)
|
||||
: GSDumpBase(fn + ".gs.xz")
|
||||
{
|
||||
m_strm = LZMA_STREAM_INIT;
|
||||
@@ -123,7 +156,7 @@ GSDumpXz::GSDumpXz(const std::string& fn, u32 crc, const freezeData& fd, const G
|
||||
return;
|
||||
}
|
||||
|
||||
AddHeader(crc, fd, regs);
|
||||
AddHeader(serial, crc, screenshot_width, screenshot_height, screenshot_pixels, fd, regs);
|
||||
}
|
||||
|
||||
GSDumpXz::~GSDumpXz()
|
||||
|
||||
+27
-6
@@ -23,7 +23,7 @@
|
||||
/*
|
||||
|
||||
Dump file format:
|
||||
- [crc/4] [state size/4] [state data/size] [PMODE/0x2000] [id/1] [data/?] .. [id/1] [data/?]
|
||||
- [0xFFFFFFFF] [Header] [state size/4] [state data/size] [PMODE/0x2000] [id/1] [data/?] .. [id/1] [data/?]
|
||||
|
||||
Transfer data (id == 0)
|
||||
- [0/1] [path index/1] [size/4] [data/size]
|
||||
@@ -39,6 +39,21 @@ Regs data (id == 3)
|
||||
|
||||
*/
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct GSDumpHeader
|
||||
{
|
||||
u32 state_version; ///< Must always be first in struct to safely prevent old PCSX2 versions from crashing.
|
||||
u32 state_size;
|
||||
u32 serial_offset;
|
||||
u32 serial_size;
|
||||
u32 crc;
|
||||
u32 screenshot_width;
|
||||
u32 screenshot_height;
|
||||
u32 screenshot_offset;
|
||||
u32 screenshot_size;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class GSDumpBase
|
||||
{
|
||||
int m_frames;
|
||||
@@ -46,7 +61,9 @@ class GSDumpBase
|
||||
FILE* m_gs;
|
||||
|
||||
protected:
|
||||
void AddHeader(u32 crc, const freezeData& fd, const GSPrivRegSet* regs);
|
||||
void AddHeader(const std::string& serial, u32 crc,
|
||||
u32 screenshot_width, u32 screenshot_height, const u32* screenshot_pixels,
|
||||
const freezeData& fd, const GSPrivRegSet* regs);
|
||||
void Write(const void* data, size_t size);
|
||||
|
||||
virtual void AppendRawData(const void* data, size_t size) = 0;
|
||||
@@ -61,14 +78,16 @@ public:
|
||||
bool VSync(int field, bool last, const GSPrivRegSet* regs);
|
||||
};
|
||||
|
||||
class GSDump final : public GSDumpBase
|
||||
class GSDumpUncompressed final : public GSDumpBase
|
||||
{
|
||||
void AppendRawData(const void* data, size_t size) final;
|
||||
void AppendRawData(u8 c) final;
|
||||
|
||||
public:
|
||||
GSDump(const std::string& fn, u32 crc, const freezeData& fd, const GSPrivRegSet* regs);
|
||||
virtual ~GSDump() = default;
|
||||
GSDumpUncompressed(const std::string& fn, const std::string& serial, u32 crc,
|
||||
u32 screenshot_width, u32 screenshot_height, const u32* screenshot_pixels,
|
||||
const freezeData& fd, const GSPrivRegSet* regs);
|
||||
virtual ~GSDumpUncompressed() = default;
|
||||
};
|
||||
|
||||
class GSDumpXz final : public GSDumpBase
|
||||
@@ -83,6 +102,8 @@ class GSDumpXz final : public GSDumpBase
|
||||
void AppendRawData(u8 c);
|
||||
|
||||
public:
|
||||
GSDumpXz(const std::string& fn, u32 crc, const freezeData& fd, const GSPrivRegSet* regs);
|
||||
GSDumpXz(const std::string& fn, const std::string& serial, u32 crc,
|
||||
u32 screenshot_width, u32 screenshot_height, const u32* screenshot_pixels,
|
||||
const freezeData& fd, const GSPrivRegSet* regs);
|
||||
virtual ~GSDumpXz();
|
||||
};
|
||||
|
||||
@@ -106,6 +106,7 @@ GSLocalMemory::GSLocalMemory()
|
||||
psm.pgs = GSVector2i(64, 32);
|
||||
psm.msk = 0xff;
|
||||
psm.depth = 0;
|
||||
psm.fmsk = 0xffffffff;
|
||||
}
|
||||
|
||||
m_psm[PSM_PSGPU24].info = GSLocalMemory::swizzle16;
|
||||
@@ -346,6 +347,17 @@ GSLocalMemory::GSLocalMemory()
|
||||
m_psm[PSM_PSMZ24].depth = 1;
|
||||
m_psm[PSM_PSMZ16].depth = 1;
|
||||
m_psm[PSM_PSMZ16S].depth = 1;
|
||||
|
||||
m_psm[PSM_PSMCT24].fmsk = 0x00FFFFFF;
|
||||
m_psm[PSM_PSGPU24].fmsk = 0x00FFFFFF;
|
||||
m_psm[PSM_PSMCT16].fmsk = 0x80F8F8F8;
|
||||
m_psm[PSM_PSMCT16S].fmsk = 0x80F8F8F8;
|
||||
m_psm[PSM_PSMT8H].fmsk = 0xFF000000;
|
||||
m_psm[PSM_PSMT4HL].fmsk = 0x0F000000;
|
||||
m_psm[PSM_PSMT4HH].fmsk = 0xF0000000;
|
||||
m_psm[PSM_PSMZ24].fmsk = 0x00FFFFFF;
|
||||
m_psm[PSM_PSMZ16].fmsk = 0x80F8F8F8;
|
||||
m_psm[PSM_PSMZ16S].fmsk = 0x80F8F8F8;
|
||||
}
|
||||
|
||||
GSLocalMemory::~GSLocalMemory()
|
||||
|
||||
@@ -468,6 +468,7 @@ public:
|
||||
u16 bpp, trbpp, pal, fmt;
|
||||
GSVector2i bs, pgs;
|
||||
u8 msk, depth;
|
||||
u32 fmsk;
|
||||
};
|
||||
|
||||
static psm_t m_psm[64];
|
||||
|
||||
+211
-43
@@ -14,28 +14,18 @@
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include "GSDump.h"
|
||||
#include "GSLzma.h"
|
||||
|
||||
GSDumpFile::GSDumpFile(char* filename, const char* repack_filename)
|
||||
{
|
||||
m_fp = fopen(filename, "rb");
|
||||
if (m_fp == nullptr)
|
||||
{
|
||||
fprintf(stderr, "failed to open %s\n", filename);
|
||||
throw "BAD"; // Just exit the program
|
||||
}
|
||||
|
||||
m_repack_fp = nullptr;
|
||||
if (repack_filename)
|
||||
{
|
||||
m_repack_fp = fopen(repack_filename, "wb");
|
||||
if (m_repack_fp == nullptr)
|
||||
fprintf(stderr, "failed to open %s for repack\n", repack_filename);
|
||||
}
|
||||
}
|
||||
using namespace GSDumpTypes;
|
||||
|
||||
GSDumpFile::GSDumpFile(FILE* file, FILE* repack_file)
|
||||
: m_repack_fp(repack_file), m_fp(file)
|
||||
: m_repack_fp(repack_file)
|
||||
, m_fp(file)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -57,13 +47,203 @@ GSDumpFile::~GSDumpFile()
|
||||
fclose(m_repack_fp);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
GSDumpLzma::GSDumpLzma(char* filename, const char* repack_filename)
|
||||
: GSDumpFile(filename, repack_filename)
|
||||
std::unique_ptr<GSDumpFile> GSDumpFile::OpenGSDump(const char* filename, const char* repack_filename /*= nullptr*/)
|
||||
{
|
||||
Initialize();
|
||||
std::FILE* fp = FileSystem::OpenCFile(filename, "rb");
|
||||
if (!fp)
|
||||
return nullptr;
|
||||
|
||||
std::FILE* repack_fp = nullptr;
|
||||
if (repack_filename && std::strlen(repack_filename) > 0)
|
||||
{
|
||||
repack_fp = FileSystem::OpenCFile(repack_filename, "wb");
|
||||
if (!repack_fp)
|
||||
{
|
||||
std::fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtil::EndsWithNoCase(filename, ".xz"))
|
||||
return std::make_unique<GSDumpLzma>(fp, nullptr);
|
||||
else
|
||||
return std::make_unique<GSDumpRaw>(fp, nullptr);
|
||||
}
|
||||
|
||||
bool GSDumpFile::GetPreviewImageFromDump(const char* filename, u32* width, u32* height, std::vector<u32>* pixels)
|
||||
{
|
||||
std::unique_ptr<GSDumpFile> dump = OpenGSDump(filename);
|
||||
if (!dump)
|
||||
return false;
|
||||
|
||||
u32 crc;
|
||||
if (!dump->Read(&crc, sizeof(crc)) || crc != 0xFFFFFFFFu)
|
||||
{
|
||||
// not new header dump, so no preview
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 header_size;
|
||||
if (!dump->Read(&header_size, sizeof(header_size)) || header_size < sizeof(GSDumpHeader))
|
||||
{
|
||||
// doesn't have the screenshot fields
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<u8[]> header_bits = std::make_unique<u8[]>(header_size);
|
||||
if (!dump->Read(header_bits.get(), header_size))
|
||||
return false;
|
||||
|
||||
GSDumpHeader header;
|
||||
std::memcpy(&header, header_bits.get(), sizeof(header));
|
||||
if (header.screenshot_size == 0 ||
|
||||
header.screenshot_size < (header.screenshot_width * header.screenshot_height * sizeof(u32)) ||
|
||||
(static_cast<u64>(header.screenshot_offset) + header.screenshot_size) > header_size)
|
||||
{
|
||||
// doesn't have a screenshot
|
||||
return false;
|
||||
}
|
||||
|
||||
*width = header.screenshot_width;
|
||||
*height = header.screenshot_height;
|
||||
pixels->resize(header.screenshot_width * header.screenshot_height);
|
||||
std::memcpy(pixels->data(), header_bits.get() + header.screenshot_offset, header.screenshot_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSDumpFile::ReadFile()
|
||||
{
|
||||
u32 ss;
|
||||
if (Read(&m_crc, sizeof(m_crc)) != sizeof(m_crc) || Read(&ss, sizeof(ss)) != sizeof(ss))
|
||||
return false;
|
||||
|
||||
m_state_data.resize(ss);
|
||||
if (Read(m_state_data.data(), ss) != ss)
|
||||
return false;
|
||||
|
||||
// Pull serial out of new header, if present.
|
||||
if (m_crc == 0xFFFFFFFFu)
|
||||
{
|
||||
GSDumpHeader header;
|
||||
if (m_state_data.size() < sizeof(header))
|
||||
{
|
||||
Console.Error("GSDump header is corrupted.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::memcpy(&header, m_state_data.data(), sizeof(header));
|
||||
|
||||
m_crc = header.crc;
|
||||
|
||||
if (header.serial_size > 0)
|
||||
{
|
||||
if (header.serial_offset > ss || (static_cast<u64>(header.serial_offset) + header.serial_size) > ss)
|
||||
{
|
||||
Console.Error("GSDump header is corrupted.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.serial_size > 0)
|
||||
m_serial.assign(reinterpret_cast<const char*>(m_state_data.data()) + header.serial_offset, header.serial_size);
|
||||
}
|
||||
|
||||
// Read the real state data
|
||||
m_state_data.resize(header.state_size);
|
||||
if (Read(m_state_data.data(), header.state_size) != header.state_size)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_regs_data.resize(8192);
|
||||
if (Read(m_regs_data.data(), m_regs_data.size()) != m_regs_data.size())
|
||||
return false;
|
||||
|
||||
// read all the packet data in
|
||||
// TODO: make this suck less by getting the full/extracted size and preallocating
|
||||
for (;;)
|
||||
{
|
||||
const size_t packet_data_size = m_packet_data.size();
|
||||
m_packet_data.resize(std::max<size_t>(packet_data_size * 2, 8 * _1mb));
|
||||
|
||||
const size_t read_size = m_packet_data.size() - packet_data_size;
|
||||
const size_t read = Read(m_packet_data.data() + packet_data_size, read_size);
|
||||
if (read != read_size)
|
||||
{
|
||||
if (!IsEof())
|
||||
return false;
|
||||
|
||||
m_packet_data.resize(packet_data_size + read);
|
||||
m_packet_data.shrink_to_fit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u8* data = m_packet_data.data();
|
||||
size_t remaining = m_packet_data.size();
|
||||
|
||||
#define GET_BYTE(dst) \
|
||||
do \
|
||||
{ \
|
||||
if (remaining < sizeof(u8)) \
|
||||
return false; \
|
||||
std::memcpy(dst, data, sizeof(u8)); \
|
||||
data++; \
|
||||
remaining--; \
|
||||
} while (0)
|
||||
#define GET_WORD(dst) \
|
||||
do \
|
||||
{ \
|
||||
if (remaining < sizeof(u32)) \
|
||||
return false; \
|
||||
std::memcpy(dst, data, sizeof(u32)); \
|
||||
data += sizeof(u32); \
|
||||
remaining -= sizeof(u32); \
|
||||
} while (0)
|
||||
|
||||
while (remaining > 0)
|
||||
{
|
||||
GSData packet = {};
|
||||
packet.path = GSTransferPath::Dummy;
|
||||
GET_BYTE(&packet.id);
|
||||
|
||||
switch (packet.id)
|
||||
{
|
||||
case GSType::Transfer:
|
||||
GET_BYTE(&packet.path);
|
||||
GET_WORD(&packet.length);
|
||||
break;
|
||||
case GSType::VSync:
|
||||
packet.length = 1;
|
||||
break;
|
||||
case GSType::ReadFIFO2:
|
||||
packet.length = 4;
|
||||
break;
|
||||
case GSType::Registers:
|
||||
packet.length = 8192;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (packet.length > 0)
|
||||
{
|
||||
if (remaining < packet.length)
|
||||
return false;
|
||||
|
||||
packet.data = data;
|
||||
data += packet.length;
|
||||
remaining -= packet.length;
|
||||
}
|
||||
|
||||
m_dump_packets.push_back(std::move(packet));
|
||||
}
|
||||
|
||||
#undef GET_WORD
|
||||
#undef GET_BYTE
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
GSDumpLzma::GSDumpLzma(FILE* file, FILE* repack_file)
|
||||
: GSDumpFile(file, repack_file)
|
||||
{
|
||||
@@ -137,11 +317,10 @@ bool GSDumpLzma::IsEof()
|
||||
return feof(m_fp) && m_avail == 0 && m_strm.avail_in == 0;
|
||||
}
|
||||
|
||||
bool GSDumpLzma::Read(void* ptr, size_t size)
|
||||
size_t GSDumpLzma::Read(void* ptr, size_t size)
|
||||
{
|
||||
size_t off = 0;
|
||||
uint8_t* dst = (uint8_t*)ptr;
|
||||
size_t full_size = size;
|
||||
while (size && !IsEof())
|
||||
{
|
||||
if (m_avail == 0)
|
||||
@@ -157,13 +336,10 @@ bool GSDumpLzma::Read(void* ptr, size_t size)
|
||||
off += l;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
Repack(ptr, full_size);
|
||||
return true;
|
||||
}
|
||||
if (off > 0)
|
||||
Repack(ptr, off);
|
||||
|
||||
return false;
|
||||
return off;
|
||||
}
|
||||
|
||||
GSDumpLzma::~GSDumpLzma()
|
||||
@@ -178,11 +354,6 @@ GSDumpLzma::~GSDumpLzma()
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
GSDumpRaw::GSDumpRaw(char* filename, const char* repack_filename)
|
||||
: GSDumpFile(filename, repack_filename)
|
||||
{
|
||||
}
|
||||
|
||||
GSDumpRaw::GSDumpRaw(FILE* file, FILE* repack_file)
|
||||
: GSDumpFile(file, repack_file)
|
||||
{
|
||||
@@ -193,20 +364,17 @@ bool GSDumpRaw::IsEof()
|
||||
return !!feof(m_fp);
|
||||
}
|
||||
|
||||
bool GSDumpRaw::Read(void* ptr, size_t size)
|
||||
size_t GSDumpRaw::Read(void* ptr, size_t size)
|
||||
{
|
||||
size_t ret = fread(ptr, 1, size, m_fp);
|
||||
if (ret != size && ferror(m_fp))
|
||||
{
|
||||
fprintf(stderr, "GSDumpRaw:: Read error (%zu/%zu)\n", ret, size);
|
||||
throw "BAD"; // Just exit the program
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == size)
|
||||
{
|
||||
Repack(ptr, size);
|
||||
return true;
|
||||
}
|
||||
if (ret > 0)
|
||||
Repack(ptr, ret);
|
||||
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
+313
-12
@@ -13,24 +13,327 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <lzma.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define GEN_REG_ENUM_CLASS_CONTENT(ClassName, EntryName, Value) \
|
||||
EntryName = Value,
|
||||
|
||||
#define GEN_REG_GETNAME_CONTENT(ClassName, EntryName, Value) \
|
||||
case ClassName::EntryName: \
|
||||
return #EntryName;
|
||||
|
||||
#define GEN_REG_ENUM_CLASS_AND_GETNAME(Macro, ClassName, Type, DefaultString) \
|
||||
enum class ClassName : Type \
|
||||
{ \
|
||||
Macro(GEN_REG_ENUM_CLASS_CONTENT) \
|
||||
}; \
|
||||
static constexpr const char* GetName(ClassName reg) \
|
||||
{ \
|
||||
switch (reg) \
|
||||
{ \
|
||||
Macro(GEN_REG_GETNAME_CONTENT) default : return DefaultString; \
|
||||
} \
|
||||
}
|
||||
|
||||
namespace GSDumpTypes
|
||||
{
|
||||
// clang-format off
|
||||
#define DEF_GSType(X) \
|
||||
X(GSType, Transfer, 0) \
|
||||
X(GSType, VSync, 1) \
|
||||
X(GSType, ReadFIFO2, 2) \
|
||||
X(GSType, Registers, 3)
|
||||
GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GSType, GSType, u8, "UnknownType")
|
||||
#undef DEF_GSType
|
||||
|
||||
#define DEF_GSTransferPath(X) \
|
||||
X(GSTransferPath, Path1Old, 0) \
|
||||
X(GSTransferPath, Path2, 1) \
|
||||
X(GSTransferPath, Path3, 2) \
|
||||
X(GSTransferPath, Path1New, 3) \
|
||||
X(GSTransferPath, Dummy, 4)
|
||||
GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GSTransferPath, GSTransferPath, u8, "UnknownPath")
|
||||
#undef DEF_GSTransferPath
|
||||
|
||||
#define DEF_GIFFlag(X) \
|
||||
X(GIFFlag, PACKED, 0) \
|
||||
X(GIFFlag, REGLIST, 1) \
|
||||
X(GIFFlag, IMAGE, 2) \
|
||||
X(GIFFlag, IMAGE2, 3)
|
||||
GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GIFFlag, GIFFlag, u8, "UnknownFlag")
|
||||
#undef DEF_GifFlag
|
||||
|
||||
#define DEF_GIFReg(X) \
|
||||
X(GIFReg, PRIM, 0x00) \
|
||||
X(GIFReg, RGBAQ, 0x01) \
|
||||
X(GIFReg, ST, 0x02) \
|
||||
X(GIFReg, UV, 0x03) \
|
||||
X(GIFReg, XYZF2, 0x04) \
|
||||
X(GIFReg, XYZ2, 0x05) \
|
||||
X(GIFReg, TEX0_1, 0x06) \
|
||||
X(GIFReg, TEX0_2, 0x07) \
|
||||
X(GIFReg, CLAMP_1, 0x08) \
|
||||
X(GIFReg, CLAMP_2, 0x09) \
|
||||
X(GIFReg, FOG, 0x0a) \
|
||||
X(GIFReg, XYZF3, 0x0c) \
|
||||
X(GIFReg, XYZ3, 0x0d) \
|
||||
X(GIFReg, AD, 0x0e) \
|
||||
X(GIFReg, NOP, 0x0f) \
|
||||
X(GIFReg, TEX1_1, 0x14) \
|
||||
X(GIFReg, TEX1_2, 0x15) \
|
||||
X(GIFReg, TEX2_1, 0x16) \
|
||||
X(GIFReg, TEX2_2, 0x17) \
|
||||
X(GIFReg, XYOFFSET_1, 0x18) \
|
||||
X(GIFReg, XYOFFSET_2, 0x19) \
|
||||
X(GIFReg, PRMODECONT, 0x1a) \
|
||||
X(GIFReg, PRMODE, 0x1b) \
|
||||
X(GIFReg, TEXCLUT, 0x1c) \
|
||||
X(GIFReg, SCANMSK, 0x22) \
|
||||
X(GIFReg, MIPTBP1_1, 0x34) \
|
||||
X(GIFReg, MIPTBP1_2, 0x35) \
|
||||
X(GIFReg, MIPTBP2_1, 0x36) \
|
||||
X(GIFReg, MIPTBP2_2, 0x37) \
|
||||
X(GIFReg, TEXA, 0x3b) \
|
||||
X(GIFReg, FOGCOL, 0x3d) \
|
||||
X(GIFReg, TEXFLUSH, 0x3f) \
|
||||
X(GIFReg, SCISSOR_1, 0x40) \
|
||||
X(GIFReg, SCISSOR_2, 0x41) \
|
||||
X(GIFReg, ALPHA_1, 0x42) \
|
||||
X(GIFReg, ALPHA_2, 0x43) \
|
||||
X(GIFReg, DIMX, 0x44) \
|
||||
X(GIFReg, DTHE, 0x45) \
|
||||
X(GIFReg, COLCLAMP, 0x46) \
|
||||
X(GIFReg, TEST_1, 0x47) \
|
||||
X(GIFReg, TEST_2, 0x48) \
|
||||
X(GIFReg, PABE, 0x49) \
|
||||
X(GIFReg, FBA_1, 0x4a) \
|
||||
X(GIFReg, FBA_2, 0x4b) \
|
||||
X(GIFReg, FRAME_1, 0x4c) \
|
||||
X(GIFReg, FRAME_2, 0x4d) \
|
||||
X(GIFReg, ZBUF_1, 0x4e) \
|
||||
X(GIFReg, ZBUF_2, 0x4f) \
|
||||
X(GIFReg, BITBLTBUF, 0x50) \
|
||||
X(GIFReg, TRXPOS, 0x51) \
|
||||
X(GIFReg, TRXREG, 0x52) \
|
||||
X(GIFReg, TRXDIR, 0x53) \
|
||||
X(GIFReg, HWREG, 0x54) \
|
||||
X(GIFReg, SIGNAL, 0x60) \
|
||||
X(GIFReg, FINISH, 0x61) \
|
||||
X(GIFReg, LABEL, 0x62)
|
||||
GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GIFReg, GIFReg, u8, "UnknownReg")
|
||||
#undef DEF_GIFReg
|
||||
// clang-format on
|
||||
|
||||
template <typename Output, typename Input, typename std::enable_if<sizeof(Input) == sizeof(Output), bool>::type = true>
|
||||
static constexpr Output BitCast(Input input)
|
||||
{
|
||||
Output output;
|
||||
memcpy(&output, &input, sizeof(input));
|
||||
return output;
|
||||
}
|
||||
template <typename Output = u32>
|
||||
static constexpr Output GetBits(u64 value, u32 shift, u32 numbits)
|
||||
{
|
||||
return static_cast<Output>((value >> shift) & ((1ull << numbits) - 1));
|
||||
}
|
||||
|
||||
template <typename Output = u32>
|
||||
static constexpr Output GetBits(u128 value, u32 shift, u32 numbits)
|
||||
{
|
||||
u64 outval = 0;
|
||||
if (shift == 0)
|
||||
outval = value.lo;
|
||||
else if (shift < 64)
|
||||
outval = (value.lo >> shift) | (value.hi << (64 - shift));
|
||||
else
|
||||
outval = value.hi >> (shift - 64);
|
||||
return static_cast<Output>(outval & ((1ull << numbits) - 1));
|
||||
}
|
||||
static constexpr const char* GetNameOneBit(u8 value, const char* zero, const char* one)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
return zero;
|
||||
case 1:
|
||||
return one;
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
static constexpr const char* GetNameBool(bool value)
|
||||
{
|
||||
return value ? "True" : "False";
|
||||
}
|
||||
|
||||
static constexpr const char* GetNamePRIMPRIM(u8 prim)
|
||||
{
|
||||
switch (prim)
|
||||
{
|
||||
case 0:
|
||||
return "Point";
|
||||
case 1:
|
||||
return "Line";
|
||||
case 2:
|
||||
return "Line Strip";
|
||||
case 3:
|
||||
return "Triangle";
|
||||
case 4:
|
||||
return "Triangle Strip";
|
||||
case 5:
|
||||
return "Triangle Fan";
|
||||
case 6:
|
||||
return "Sprite";
|
||||
case 7:
|
||||
return "Invalid";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
static constexpr const char* GetNamePRIMIIP(u8 iip)
|
||||
{
|
||||
return GetNameOneBit(iip, "Flat Shading", "Gouraud Shading");
|
||||
}
|
||||
static constexpr const char* GetNamePRIMFST(u8 fst)
|
||||
{
|
||||
return GetNameOneBit(fst, "STQ Value", "UV Value");
|
||||
}
|
||||
static constexpr const char* GetNamePRIMCTXT(u8 ctxt)
|
||||
{
|
||||
return GetNameOneBit(ctxt, "Context 1", "Context 2");
|
||||
}
|
||||
static constexpr const char* GetNamePRIMFIX(u8 fix)
|
||||
{
|
||||
return GetNameOneBit(fix, "Unfixed", "Fixed");
|
||||
}
|
||||
static constexpr const char* GetNameTEXTCC(u8 tcc)
|
||||
{
|
||||
return GetNameOneBit(tcc, "RGB", "RGBA");
|
||||
}
|
||||
static constexpr const char* GetNameTEXTFX(u8 tfx)
|
||||
{
|
||||
switch (tfx)
|
||||
{
|
||||
case 0:
|
||||
return "Modulate";
|
||||
case 1:
|
||||
return "Decal";
|
||||
case 2:
|
||||
return "Highlight";
|
||||
case 3:
|
||||
return "Highlight2";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
static constexpr const char* GetNameTEXCSM(u8 csm)
|
||||
{
|
||||
return GetNameOneBit(csm, "CSM1", "CSM2");
|
||||
}
|
||||
static constexpr const char* GetNameTEXPSM(u8 psm)
|
||||
{
|
||||
switch (psm)
|
||||
{
|
||||
case 000:
|
||||
return "PSMCT32";
|
||||
case 001:
|
||||
return "PSMCT24";
|
||||
case 002:
|
||||
return "PSMCT16";
|
||||
case 012:
|
||||
return "PSMCT16S";
|
||||
case 023:
|
||||
return "PSMT8";
|
||||
case 024:
|
||||
return "PSMT4";
|
||||
case 033:
|
||||
return "PSMT8H";
|
||||
case 044:
|
||||
return "PSMT4HL";
|
||||
case 054:
|
||||
return "PSMT4HH";
|
||||
case 060:
|
||||
return "PSMZ32";
|
||||
case 061:
|
||||
return "PSMZ24";
|
||||
case 062:
|
||||
return "PSMZ16";
|
||||
case 072:
|
||||
return "PSMZ16S";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
static constexpr const char* GetNameTEXCPSM(u8 psm)
|
||||
{
|
||||
switch (psm)
|
||||
{
|
||||
case 000:
|
||||
return "PSMCT32";
|
||||
case 002:
|
||||
return "PSMCT16";
|
||||
case 012:
|
||||
return "PSMCT16S";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
} // namespace GSDumpTypes
|
||||
|
||||
class GSDumpFile
|
||||
{
|
||||
FILE* m_repack_fp;
|
||||
public:
|
||||
struct GSData
|
||||
{
|
||||
GSDumpTypes::GSType id;
|
||||
const u8* data;
|
||||
s32 length;
|
||||
GSDumpTypes::GSTransferPath path;
|
||||
};
|
||||
|
||||
using ByteArray = std::vector<u8>;
|
||||
using GSDataArray = std::vector<GSData>;
|
||||
|
||||
virtual ~GSDumpFile();
|
||||
|
||||
static std::unique_ptr<GSDumpFile> OpenGSDump(const char* filename, const char* repack_filename = nullptr);
|
||||
static bool GetPreviewImageFromDump(const char* filename, u32* width, u32* height, std::vector<u32>* pixels);
|
||||
|
||||
__fi const std::string& GetSerial() const { return m_serial; }
|
||||
__fi u32 GetCRC() const { return m_crc; }
|
||||
|
||||
__fi const ByteArray& GetRegsData() const { return m_regs_data; }
|
||||
__fi const ByteArray& GetStateData() const { return m_state_data; }
|
||||
__fi const GSDataArray& GetPackets() const { return m_dump_packets; }
|
||||
|
||||
bool ReadFile();
|
||||
|
||||
protected:
|
||||
FILE* m_fp;
|
||||
GSDumpFile(FILE* file, FILE* repack_file);
|
||||
|
||||
virtual bool IsEof() = 0;
|
||||
virtual size_t Read(void* ptr, size_t size) = 0;
|
||||
|
||||
void Repack(void* ptr, size_t size);
|
||||
|
||||
public:
|
||||
virtual bool IsEof() = 0;
|
||||
virtual bool Read(void* ptr, size_t size) = 0;
|
||||
FILE* m_fp = nullptr;
|
||||
|
||||
GSDumpFile(char* filename, const char* repack_filename);
|
||||
GSDumpFile(FILE* file, FILE* repack_file);
|
||||
virtual ~GSDumpFile();
|
||||
private:
|
||||
FILE* m_repack_fp = nullptr;
|
||||
|
||||
std::string m_serial;
|
||||
u32 m_crc = 0;
|
||||
|
||||
std::vector<u8> m_regs_data;
|
||||
std::vector<u8> m_state_data;
|
||||
std::vector<u8> m_packet_data;
|
||||
|
||||
GSDataArray m_dump_packets;
|
||||
};
|
||||
|
||||
class GSDumpLzma : public GSDumpFile
|
||||
@@ -48,21 +351,19 @@ class GSDumpLzma : public GSDumpFile
|
||||
void Initialize();
|
||||
|
||||
public:
|
||||
GSDumpLzma(char* filename, const char* repack_filename);
|
||||
GSDumpLzma(FILE* file, FILE* repack_file);
|
||||
virtual ~GSDumpLzma();
|
||||
|
||||
bool IsEof() final;
|
||||
bool Read(void* ptr, size_t size) final;
|
||||
size_t Read(void* ptr, size_t size) final;
|
||||
};
|
||||
|
||||
class GSDumpRaw : public GSDumpFile
|
||||
{
|
||||
public:
|
||||
GSDumpRaw(char* filename, const char* repack_filename);
|
||||
GSDumpRaw(FILE* file, FILE* repack_file);
|
||||
virtual ~GSDumpRaw() = default;
|
||||
|
||||
bool IsEof() final;
|
||||
bool Read(void* ptr, size_t size) final;
|
||||
size_t Read(void* ptr, size_t size) final;
|
||||
};
|
||||
|
||||
@@ -26,9 +26,6 @@ GSPerfMon::GSPerfMon()
|
||||
{
|
||||
memset(m_counters, 0, sizeof(m_counters));
|
||||
memset(m_stats, 0, sizeof(m_stats));
|
||||
memset(m_timer_stats, 0, sizeof(m_timer_stats));
|
||||
memset(m_total, 0, sizeof(m_total));
|
||||
memset(m_begin, 0, sizeof(m_begin));
|
||||
}
|
||||
|
||||
void GSPerfMon::EndFrame()
|
||||
@@ -39,7 +36,6 @@ void GSPerfMon::EndFrame()
|
||||
|
||||
void GSPerfMon::Update()
|
||||
{
|
||||
#ifndef DISABLE_PERF_MON
|
||||
if (m_count > 0)
|
||||
{
|
||||
for (size_t i = 0; i < std::size(m_counters); i++)
|
||||
@@ -48,55 +44,7 @@ void GSPerfMon::Update()
|
||||
}
|
||||
|
||||
m_count = 0;
|
||||
|
||||
// Update CPU usage for SW renderer.
|
||||
if (GSConfig.Renderer == GSRendererType::SW)
|
||||
{
|
||||
const u64 current = __rdtsc();
|
||||
|
||||
for (size_t i = WorkerDraw0; i < TimerLast; i++)
|
||||
{
|
||||
if (m_begin[i] == 0)
|
||||
{
|
||||
m_timer_stats[i] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_timer_stats[i] =
|
||||
static_cast<float>(static_cast<double>(m_total[i]) / static_cast<double>(current - m_begin[i])
|
||||
* 100.0);
|
||||
|
||||
m_begin[i] = 0;
|
||||
m_start[i] = 0;
|
||||
m_total[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
memset(m_counters, 0, sizeof(m_counters));
|
||||
#endif
|
||||
}
|
||||
|
||||
void GSPerfMon::Start(int timer)
|
||||
{
|
||||
#ifndef DISABLE_PERF_MON
|
||||
m_start[timer] = __rdtsc();
|
||||
|
||||
if (m_begin[timer] == 0)
|
||||
{
|
||||
m_begin[timer] = m_start[timer];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GSPerfMon::Stop(int timer)
|
||||
{
|
||||
#ifndef DISABLE_PERF_MON
|
||||
if (m_start[timer] > 0)
|
||||
{
|
||||
m_total[timer] += __rdtsc() - m_start[timer];
|
||||
m_start[timer] = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -18,14 +18,6 @@
|
||||
class GSPerfMon
|
||||
{
|
||||
public:
|
||||
enum timer_t
|
||||
{
|
||||
Main,
|
||||
Sync,
|
||||
WorkerDraw0,
|
||||
TimerLast = WorkerDraw0 + 32, // Enough space for 32 GS worker threads
|
||||
};
|
||||
|
||||
enum counter_t
|
||||
{
|
||||
Prim,
|
||||
@@ -47,15 +39,11 @@ public:
|
||||
protected:
|
||||
double m_counters[CounterLast];
|
||||
double m_stats[CounterLast];
|
||||
float m_timer_stats[TimerLast];
|
||||
u64 m_begin[TimerLast], m_total[TimerLast], m_start[TimerLast];
|
||||
u64 m_frame;
|
||||
clock_t m_lastframe;
|
||||
int m_count;
|
||||
int m_disp_fb_sprite_blits;
|
||||
|
||||
friend class GSPerfMonAutoTimer;
|
||||
|
||||
public:
|
||||
GSPerfMon();
|
||||
|
||||
@@ -65,12 +53,8 @@ public:
|
||||
|
||||
void Put(counter_t c, double val = 0) { m_counters[c] += val; }
|
||||
double Get(counter_t c) { return m_stats[c]; }
|
||||
float GetTimer(timer_t t) { return m_timer_stats[t]; }
|
||||
void Update();
|
||||
|
||||
void Start(int timer = Main);
|
||||
void Stop(int timer = Main);
|
||||
|
||||
__fi void AddDisplayFramebufferSpriteBlit() { m_disp_fb_sprite_blits++; }
|
||||
__fi int GetDisplayFramebufferSpriteBlits()
|
||||
{
|
||||
@@ -80,18 +64,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class GSPerfMonAutoTimer
|
||||
{
|
||||
GSPerfMon* m_pm;
|
||||
int m_timer;
|
||||
|
||||
public:
|
||||
GSPerfMonAutoTimer(GSPerfMon* pm, int timer = GSPerfMon::Main)
|
||||
{
|
||||
m_timer = timer;
|
||||
(m_pm = pm)->Start(m_timer);
|
||||
}
|
||||
~GSPerfMonAutoTimer() { m_pm->Stop(m_timer); }
|
||||
};
|
||||
|
||||
extern GSPerfMon g_perfmon;
|
||||
+271
-102
@@ -20,17 +20,29 @@
|
||||
|
||||
#include <algorithm> // clamp
|
||||
#include <cfloat> // FLT_MAX
|
||||
#include <iomanip> // Dump Verticles
|
||||
|
||||
int GSState::s_n = 0;
|
||||
|
||||
static __fi bool IsAutoFlushEnabled()
|
||||
{
|
||||
return (GSConfig.Renderer == GSRendererType::SW) ? GSConfig.AutoFlushSW : GSConfig.UserHacks_AutoFlush;
|
||||
}
|
||||
|
||||
static __fi bool IsFirstProvokingVertex()
|
||||
{
|
||||
return (GSConfig.Renderer != GSRendererType::SW && !g_gs_device->Features().provoking_vertex_last);
|
||||
}
|
||||
|
||||
GSState::GSState()
|
||||
: m_version(7)
|
||||
: m_version(STATE_VERSION)
|
||||
, m_gsc(NULL)
|
||||
, m_skip(0)
|
||||
, m_skip_offset(0)
|
||||
, m_q(1.0f)
|
||||
, m_scanmask_used(false)
|
||||
, m_vt(this)
|
||||
, tex_flushed(true)
|
||||
, m_vt(this, IsFirstProvokingVertex())
|
||||
, m_regs(NULL)
|
||||
, m_crc(0)
|
||||
, m_options(0)
|
||||
@@ -39,18 +51,8 @@ GSState::GSState()
|
||||
// m_nativeres seems to be a hack. Unfortunately it impacts draw call number which make debug painful in the replayer.
|
||||
// Let's keep it disabled to ease debug.
|
||||
m_nativeres = GSConfig.UpscaleMultiplier == 1;
|
||||
m_mipmap = theApp.GetConfigB("mipmap");
|
||||
m_mipmap = GSConfig.Mipmap;
|
||||
m_NTSC_Saturation = theApp.GetConfigB("NTSC_Saturation");
|
||||
if (theApp.GetConfigB("UserHacks"))
|
||||
{
|
||||
m_userhacks_auto_flush = theApp.GetConfigB("UserHacks_AutoFlush");
|
||||
m_userhacks_wildhack = theApp.GetConfigB("UserHacks_WildHack");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_userhacks_auto_flush = false;
|
||||
m_userhacks_wildhack = false;
|
||||
}
|
||||
|
||||
s_n = 0;
|
||||
s_dump = theApp.GetConfigB("dump");
|
||||
@@ -132,7 +134,6 @@ GSState::GSState()
|
||||
PRIM = &m_env.PRIM;
|
||||
//CSR->rREV = 0x20;
|
||||
m_env.PRMODECONT.AC = 1;
|
||||
tex_flushed = true;
|
||||
|
||||
Reset();
|
||||
|
||||
@@ -246,7 +247,7 @@ void GSState::ResetHandlers()
|
||||
m_fpGIFPackedRegHandlers[GIF_REG_PRIM] = (GIFPackedRegHandler)(GIFRegHandler)&GSState::GIFRegHandlerPRIM;
|
||||
m_fpGIFPackedRegHandlers[GIF_REG_RGBA] = &GSState::GIFPackedRegHandlerRGBA;
|
||||
m_fpGIFPackedRegHandlers[GIF_REG_STQ] = &GSState::GIFPackedRegHandlerSTQ;
|
||||
m_fpGIFPackedRegHandlers[GIF_REG_UV] = m_userhacks_wildhack ? &GSState::GIFPackedRegHandlerUV_Hack : &GSState::GIFPackedRegHandlerUV;
|
||||
m_fpGIFPackedRegHandlers[GIF_REG_UV] = GSConfig.UserHacks_WildHack ? &GSState::GIFPackedRegHandlerUV_Hack : &GSState::GIFPackedRegHandlerUV;
|
||||
m_fpGIFPackedRegHandlers[GIF_REG_TEX0_1] = (GIFPackedRegHandler)(GIFRegHandler)&GSState::GIFRegHandlerTEX0<0>;
|
||||
m_fpGIFPackedRegHandlers[GIF_REG_TEX0_2] = (GIFPackedRegHandler)(GIFRegHandler)&GSState::GIFRegHandlerTEX0<1>;
|
||||
m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_1] = (GIFPackedRegHandler)(GIFRegHandler)&GSState::GIFRegHandlerCLAMP<0>;
|
||||
@@ -256,11 +257,10 @@ void GSState::ResetHandlers()
|
||||
m_fpGIFPackedRegHandlers[GIF_REG_NOP] = &GSState::GIFPackedRegHandlerNOP;
|
||||
|
||||
// swap first/last indices when the provoking vertex is the first (D3D/Vulkan)
|
||||
const bool index_swap = GSConfig.UseHardwareRenderer() && !g_gs_device->Features().provoking_vertex_last;
|
||||
if (m_userhacks_auto_flush)
|
||||
index_swap ? SetPrimHandlers<true, true>() : SetPrimHandlers<true, false>();
|
||||
if (IsAutoFlushEnabled())
|
||||
IsFirstProvokingVertex() ? SetPrimHandlers<true, true>() : SetPrimHandlers<true, false>();
|
||||
else
|
||||
index_swap ? SetPrimHandlers<false, true>() : SetPrimHandlers<false, false>();
|
||||
IsFirstProvokingVertex() ? SetPrimHandlers<false, true>() : SetPrimHandlers<false, false>();
|
||||
|
||||
std::fill(std::begin(m_fpGIFRegHandlers), std::end(m_fpGIFRegHandlers), &GSState::GIFRegHandlerNull);
|
||||
|
||||
@@ -268,7 +268,7 @@ void GSState::ResetHandlers()
|
||||
m_fpGIFRegHandlers[GIF_A_D_REG_RGBAQ] = &GSState::GIFRegHandlerRGBAQ;
|
||||
m_fpGIFRegHandlers[GIF_A_D_REG_RGBAQ + 0x10] = &GSState::GIFRegHandlerRGBAQ;
|
||||
m_fpGIFRegHandlers[GIF_A_D_REG_ST] = &GSState::GIFRegHandlerST;
|
||||
m_fpGIFRegHandlers[GIF_A_D_REG_UV] = m_userhacks_wildhack ? &GSState::GIFRegHandlerUV_Hack : &GSState::GIFRegHandlerUV;
|
||||
m_fpGIFRegHandlers[GIF_A_D_REG_UV] = GSConfig.UserHacks_WildHack ? &GSState::GIFRegHandlerUV_Hack : &GSState::GIFRegHandlerUV;
|
||||
m_fpGIFRegHandlers[GIF_A_D_REG_TEX0_1] = &GSState::GIFRegHandlerTEX0<0>;
|
||||
m_fpGIFRegHandlers[GIF_A_D_REG_TEX0_2] = &GSState::GIFRegHandlerTEX0<1>;
|
||||
m_fpGIFRegHandlers[GIF_A_D_REG_CLAMP_1] = &GSState::GIFRegHandlerCLAMP<0>;
|
||||
@@ -319,6 +319,19 @@ void GSState::ResetHandlers()
|
||||
m_fpGIFRegHandlers[GIF_A_D_REG_LABEL] = &GSState::GIFRegHandlerNull;
|
||||
}
|
||||
|
||||
void GSState::UpdateSettings(const Pcsx2Config::GSOptions& old_config)
|
||||
{
|
||||
m_mipmap = GSConfig.Mipmap;
|
||||
|
||||
if (
|
||||
GSConfig.AutoFlushSW != old_config.AutoFlushSW ||
|
||||
GSConfig.UserHacks_AutoFlush != old_config.UserHacks_AutoFlush ||
|
||||
GSConfig.UserHacks_WildHack != old_config.UserHacks_WildHack)
|
||||
{
|
||||
ResetHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
bool GSState::isinterlaced()
|
||||
{
|
||||
return !!m_regs->SMODE2.INT;
|
||||
@@ -543,6 +556,100 @@ float GSState::GetTvRefreshRate()
|
||||
__assume(0); // unreachable
|
||||
}
|
||||
|
||||
void GSState::DumpVertices(const std::string& filename)
|
||||
{
|
||||
std::ofstream file(filename);
|
||||
|
||||
if (!file.is_open())
|
||||
return;
|
||||
|
||||
size_t count = m_index.tail;
|
||||
GSVertex* buffer = &m_vertex.buff[0];
|
||||
|
||||
const char* DEL = ", ";
|
||||
|
||||
file << "VERTEX COORDS (XYZ)" << std::endl;
|
||||
file << std::fixed << std::setprecision(4);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
file << "\t" << "v" << i << ": ";
|
||||
GSVertex v = buffer[m_index.buff[i]];
|
||||
|
||||
float x = (v.XYZ.X - (int)m_context->XYOFFSET.OFX) / 16.0f;
|
||||
float y = (v.XYZ.Y - (int)m_context->XYOFFSET.OFY) / 16.0f;
|
||||
|
||||
file << x << DEL;
|
||||
file << y << DEL;
|
||||
file << v.XYZ.Z;
|
||||
file << std::endl;
|
||||
}
|
||||
|
||||
file << std::endl;
|
||||
|
||||
file << "VERTEX COLOR (RGBA)" << std::endl;
|
||||
file << std::fixed << std::setprecision(6);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
file << "\t" << "v" << i << ": ";
|
||||
GSVertex v = buffer[m_index.buff[i]];
|
||||
|
||||
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.R) << DEL;
|
||||
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.G) << DEL;
|
||||
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.B) << DEL;
|
||||
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.A);
|
||||
file << std::endl;
|
||||
}
|
||||
|
||||
file << std::endl;
|
||||
|
||||
bool use_uv = PRIM->FST;
|
||||
std::string qualifier = use_uv ? "UV" : "STQ";
|
||||
|
||||
file << "TEXTURE COORDS (" << qualifier << ")" << std::endl;;
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
file << "\t" << "v" << i << ": ";
|
||||
GSVertex v = buffer[m_index.buff[i]];
|
||||
|
||||
// note
|
||||
// Yes, technically as far as the GS is concerned Q belongs
|
||||
// to RGBAQ. However, the purpose of this dump is to print
|
||||
// our data in a more human readable format and typically Q
|
||||
// is associated with STQ.
|
||||
if (use_uv)
|
||||
{
|
||||
float uv_U = v.U / 16.0f;
|
||||
float uv_V = v.V / 16.0f;
|
||||
|
||||
file << uv_U << DEL << uv_V;
|
||||
}
|
||||
else
|
||||
file << v.ST.S << DEL << v.ST.T << DEL << v.RGBAQ.Q;
|
||||
|
||||
file << std::endl;
|
||||
}
|
||||
|
||||
file << std::endl;
|
||||
|
||||
file << "TRACER" << std::endl;
|
||||
|
||||
GSVector4i v = m_vt.m_min.c;
|
||||
file << "\tmin c (x,y,z,w): " << v.x << DEL << v.y << DEL << v.z << DEL << v.w << std::endl;
|
||||
v = m_vt.m_max.c;
|
||||
file << "\tmax c (x,y,z,w): " << v.x << DEL << v.y << DEL << v.z << DEL << v.w << std::endl;
|
||||
|
||||
GSVector4 v2 = m_vt.m_min.p;
|
||||
file << "\tmin p (x,y,z,w): " << v2.x << DEL << v2.y << DEL << v2.z << DEL << v2.w << std::endl;
|
||||
v2 = m_vt.m_max.p;
|
||||
file << "\tmax p (x,y,z,w): " << v2.x << DEL << v2.y << DEL << v2.z << DEL << v2.w << std::endl;
|
||||
v2 = m_vt.m_min.t;
|
||||
file << "\tmin t (x,y,z,w): " << v2.x << DEL << v2.y << DEL << v2.z << DEL << v2.w << std::endl;
|
||||
v2 = m_vt.m_max.t;
|
||||
file << "\tmax t (x,y,z,w): " << v2.x << DEL << v2.y << DEL << v2.z << DEL << v2.w << std::endl;
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void GSState::GIFPackedRegHandlerNull(const GIFPackedReg* RESTRICT r)
|
||||
{
|
||||
}
|
||||
@@ -894,7 +1001,10 @@ void GSState::GIFRegHandlerTEX0(const GIFReg* RESTRICT r)
|
||||
GL_REG("TEX0_%d = 0x%x_%x", i, r->U32[1], r->U32[0]);
|
||||
|
||||
GIFRegTEX0 TEX0 = r->TEX0;
|
||||
const bool MTBAreload = ((tex_flushed && (i == m_env.PRIM.CTXT)) || (r->TEX0.TBP0 != m_env.CTXT[i].TEX0.TBP0)) ? true : false;
|
||||
GIFRegMIPTBP1 temp_MIPTBP1;
|
||||
bool MTBAReloaded = false;
|
||||
// Max allowed MTBA size for 32bit swizzled textures (including 8H 4HL etc) is 512, 16bit and normal 8/4bit formats can be 1024
|
||||
const u32 maxTex = (GSLocalMemory::m_psm[TEX0.PSM].bpp < 32) ? 10 : 9;
|
||||
|
||||
// Spec max is 10
|
||||
//
|
||||
@@ -910,61 +1020,53 @@ void GSState::GIFRegHandlerTEX0(const GIFReg* RESTRICT r)
|
||||
TEX0.TW = std::clamp<u32>(TEX0.TW, 0, 10);
|
||||
TEX0.TH = std::clamp<u32>(TEX0.TH, 0, 10);
|
||||
|
||||
ApplyTEX0<i>(TEX0);
|
||||
|
||||
// When the texture cache reloads any MIPS need to update too, so let's do that here.
|
||||
// This is essentially triggered by the texture page change, so if TEXFLUSH is called and a draw doesn't proceed it, or TBP changes.
|
||||
// Textures must be of equal width/height and a minimum of 32x32
|
||||
if (MTBAreload && m_env.CTXT[i].TEX1.MTBA && m_env.CTXT[i].TEX0.TW == m_env.CTXT[i].TEX0.TH && m_env.CTXT[i].TEX0.TW >= 5)
|
||||
// MTBA loads are triggered by writes to TEX0 (but not TEX2!)
|
||||
// Textures MUST be a minimum width of 32 pixels
|
||||
// Format must be a color, Z formats do not trigger MTBA (but are valid for Mipmapping)
|
||||
if (m_env.CTXT[i].TEX1.MTBA && TEX0.TW >= 5 && TEX0.TW <= maxTex && (TEX0.PSM & 0x30) != 0x30)
|
||||
{
|
||||
// NOTE 1: TEX1.MXL must not be automatically set to 3 here.
|
||||
// NOTE 2: Mipmap levels are tightly packed, if (tbw << 6) > (1 << tw) then the left-over space to the right is used. (common for PSM_PSMT4)
|
||||
// NOTE 3: Non-rectangular textures are treated as rectangular when calculating the occupied space (height is extended, not sure about width)
|
||||
// NOTE 1: TEX1.MXL must not be automatically set to 3 here and it has no effect on MTBA.
|
||||
// NOTE 2: Mipmap levels are packed with a minimum distance between them of 1 block, even down at 4bit textures under 16x16.
|
||||
// NOTE 3: Everything is derrived from the width of the texture, TBW and TH are completely ignored (useful for handling non-rectangular ones)
|
||||
// NOTE 4: Cartoon Network Racing's menu is VERY sensitive to this as it uses 4bit sized textures for the sky.
|
||||
u32 bp = TEX0.TBP0;
|
||||
u32 bw = std::max(1u, (1u << TEX0.TW) >> 6);
|
||||
|
||||
u32 bp = m_env.CTXT[i].TEX0.TBP0;
|
||||
u32 bw = m_env.CTXT[i]. TEX0.TBW;
|
||||
u32 w = 1u << m_env.CTXT[i].TEX0.TW;
|
||||
u32 h = 1u << m_env.CTXT[i].TEX0.TH;
|
||||
u32 minwidth = m_env.CTXT[i].TEX1.MMIN >= 4 ? 8 : 1;
|
||||
// Address is calculated as a 4bit address space, then converted (/8) to 32bit address space
|
||||
// ((w * w * bpp) / 8) / 64. No the 'w' is not a typo ;)
|
||||
const u32 bpp = GSLocalMemory::m_psm[TEX0.PSM].bpp >> 2;
|
||||
u32 tex_size = ((1u << TEX0.TW) * (1u << TEX0.TW) * bpp) >> 9;
|
||||
|
||||
const u32 bpp = GSLocalMemory::m_psm[m_env.CTXT[i].TEX0.PSM].bpp;
|
||||
bp += tex_size;
|
||||
bw = std::max<u32>(bw >> 1, 1);
|
||||
tex_size = std::max<u32>(tex_size >> 2, 1);
|
||||
|
||||
bp += (int)((w * h * ((float)bpp / 8))) >> 8;
|
||||
temp_MIPTBP1.TBP1 = bp;
|
||||
temp_MIPTBP1.TBW1 = bw;
|
||||
|
||||
if (w > minwidth)
|
||||
{
|
||||
bw = std::max<u32>(bw >> 1, 1);
|
||||
w = std::max<u32>(w >> 1, 1);
|
||||
h = std::max<u32>(h >> 1, 1);
|
||||
}
|
||||
bp += tex_size;
|
||||
bw = std::max<u32>(bw >> 1, 1);
|
||||
tex_size = std::max<u32>(tex_size >> 2, 1);
|
||||
|
||||
m_env.CTXT[i].MIPTBP1.TBP1 = bp;
|
||||
m_env.CTXT[i].MIPTBP1.TBW1 = bw;
|
||||
temp_MIPTBP1.TBP2 = bp;
|
||||
temp_MIPTBP1.TBW2 = bw;
|
||||
|
||||
bp += (int)((w * h * ((float)bpp / 8))) >> 8;
|
||||
bp += tex_size;
|
||||
bw = std::max<u32>(bw >> 1, 1);
|
||||
|
||||
if (w > minwidth)
|
||||
{
|
||||
bw = std::max<u32>(bw >> 1, 1);
|
||||
w = std::max<u32>(w >> 1, 1);
|
||||
h = std::max<u32>(h >> 1, 1);
|
||||
}
|
||||
temp_MIPTBP1.TBP3 = bp;
|
||||
temp_MIPTBP1.TBW3 = bw;
|
||||
|
||||
m_env.CTXT[i].MIPTBP1.TBP2 = bp;
|
||||
m_env.CTXT[i].MIPTBP1.TBW2 = bw;
|
||||
if (temp_MIPTBP1 != m_env.CTXT[i].MIPTBP1)
|
||||
Flush();
|
||||
|
||||
bp += (int)((w * h * ((float)bpp / 8))) >> 8;
|
||||
|
||||
if (w > minwidth)
|
||||
{
|
||||
bw = std::max<u32>(bw >> 1, 1);
|
||||
}
|
||||
|
||||
m_env.CTXT[i].MIPTBP1.TBP3 = bp;
|
||||
m_env.CTXT[i].MIPTBP1.TBW3 = bw;
|
||||
MTBAReloaded = true;
|
||||
}
|
||||
|
||||
tex_flushed = false;
|
||||
ApplyTEX0<i>(TEX0);
|
||||
|
||||
if (MTBAReloaded)
|
||||
m_env.CTXT[i].MIPTBP1 = temp_MIPTBP1;
|
||||
}
|
||||
|
||||
template <int i>
|
||||
@@ -1132,11 +1234,10 @@ void GSState::GIFRegHandlerTEXFLUSH(const GIFReg* RESTRICT r)
|
||||
{
|
||||
GL_REG("TEXFLUSH = 0x%x_%x PRIM TME %x", r->U32[1], r->U32[0], PRIM->TME);
|
||||
|
||||
tex_flushed = true;
|
||||
// Some games do a single sprite draw to itself, then flush the texture cache, then use that texture again.
|
||||
// This won't get picked up by the new autoflush logic (which checks for page crossings for the PS2 Texture Cache flush)
|
||||
// so we need to do it here.
|
||||
if(m_userhacks_auto_flush)
|
||||
if (IsAutoFlushEnabled())
|
||||
Flush();
|
||||
}
|
||||
|
||||
@@ -1705,14 +1806,59 @@ void GSState::Move()
|
||||
int _sy = sy, _dy = dy; // Faster with local copied variables, compiler optimizations are dumb
|
||||
if (xinc > 0)
|
||||
{
|
||||
for (int y = 0; y < h; y++, _sy += yinc, _dy += yinc)
|
||||
const int page_width = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].pgs.x;
|
||||
const int page_height = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].pgs.y;
|
||||
const int xpage = sx & ~(page_width - 1);
|
||||
const int ypage = _sy & ~(page_height - 1);
|
||||
// Copying from itself to itself (rotating textures) used in Gitaroo Man stage 8
|
||||
// What probably happens is because the copy is buffered, the source stays just ahead of the destination.
|
||||
if (sbp == dbp && (((_sy < _dy) && ((ypage + page_height) > _dy)) || ((sx < dx) && ((xpage + page_width) > dx))))
|
||||
{
|
||||
auto s = getPAHelper(spo, sx, _sy);
|
||||
auto d = getPAHelper(dpo, dx, _dy);
|
||||
int starty = 0;
|
||||
int endy = h;
|
||||
int y_inc = yinc;
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
if (((_sy < _dy) && ((ypage + page_height) > _dy)))
|
||||
{
|
||||
pxCopyFn(d, s, x);
|
||||
_sy += h;
|
||||
_dy += h;
|
||||
starty = h-1;
|
||||
endy = -1;
|
||||
y_inc = -y_inc;
|
||||
}
|
||||
|
||||
for (int y = starty; y != endy; y+= y_inc, _sy += y_inc, _dy += y_inc)
|
||||
{
|
||||
auto s = getPAHelper(spo, sx, _sy);
|
||||
auto d = getPAHelper(dpo, dx, _dy);
|
||||
|
||||
if (((sx < dx) && ((xpage + page_width) > dx)))
|
||||
{
|
||||
for (int x = w - 1; x >= 0; x--)
|
||||
{
|
||||
pxCopyFn(d, s, x);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
pxCopyFn(d, s, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < h; y++, _sy += yinc, _dy += yinc)
|
||||
{
|
||||
auto s = getPAHelper(spo, sx, _sy);
|
||||
auto d = getPAHelper(dpo, dx, _dy);
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
pxCopyFn(d, s, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1819,8 +1965,6 @@ void GSState::SoftReset(u32 mask)
|
||||
|
||||
void GSState::ReadFIFO(u8* mem, int size)
|
||||
{
|
||||
GSPerfMonAutoTimer pmat(&g_perfmon);
|
||||
|
||||
Flush();
|
||||
|
||||
size *= 16;
|
||||
@@ -1839,8 +1983,6 @@ template void GSState::Transfer<3>(const u8* mem, u32 size);
|
||||
template <int index>
|
||||
void GSState::Transfer(const u8* mem, u32 size)
|
||||
{
|
||||
GSPerfMonAutoTimer pmat(&g_perfmon);
|
||||
|
||||
const u8* start = mem;
|
||||
|
||||
GIFPath& path = m_path[index];
|
||||
@@ -2127,7 +2269,7 @@ int GSState::Defrost(const freezeData* fd)
|
||||
|
||||
u8* data = fd->data;
|
||||
|
||||
int version;
|
||||
u32 version;
|
||||
|
||||
ReadState(&version, data);
|
||||
|
||||
@@ -2433,10 +2575,17 @@ GSState::PRIM_OVERLAP GSState::PrimitiveOverlap()
|
||||
|
||||
__forceinline void GSState::HandleAutoFlush()
|
||||
{
|
||||
const u32 frame_mask = GSLocalMemory::m_psm[m_context->TEX0.PSM].fmsk;
|
||||
const bool frame_hit = (m_context->FRAME.Block() == m_context->TEX0.TBP0) && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL == 2) && ((m_context->FRAME.FBMSK & frame_mask) != frame_mask);
|
||||
// There's a strange behaviour we need to test on a PS2 here, if the FRAME is a Z format, like Powerdrome something swaps over, and it seems Alpha Fail of "FB Only" writes to the Z.. it's odd.
|
||||
const bool zbuf_hit = (m_context->ZBUF.Block() == m_context->TEX0.TBP0) && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL != 2) && !m_context->ZBUF.ZMSK;
|
||||
const u32 frame_z_psm = frame_hit ? m_context->FRAME.PSM : m_context->ZBUF.PSM;
|
||||
const u32 frame_z_bp = frame_hit ? m_context->FRAME.Block() : m_context->ZBUF.Block();
|
||||
|
||||
// To briefly explain what's going on here, what we are checking for is draws over a texture when the source and destination are themselves.
|
||||
// Because one page of the texture gets buffered in the Texture Cache (the PS2's one) if any of those pixels are overwritten, you still read the old data.
|
||||
// So we need to calculate if a page boundary is being crossed for the format it is in and if the same part of the texture being written and read inside the draw.
|
||||
if ((m_context->FRAME.Block() == m_context->TEX0.TBP0) && (m_context->TEX0.PSM == m_context->FRAME.PSM) && PRIM->TME && (m_context->FRAME.FBMSK != 0xFFFFFFFF))
|
||||
if (PRIM->TME && (frame_hit || zbuf_hit) && GSUtil::HasSharedBits(frame_z_bp, frame_z_psm, m_context->TEX0.TBP0, m_context->TEX0.PSM))
|
||||
{
|
||||
const int page_mask_x = ~(GSLocalMemory::m_psm[m_context->TEX0.PSM].pgs.x - 1);
|
||||
const int page_mask_y = ~(GSLocalMemory::m_psm[m_context->TEX0.PSM].pgs.y - 1);
|
||||
@@ -2513,14 +2662,46 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
|
||||
if(page_crossed)
|
||||
{
|
||||
// Update the vertex trace, scissor it (important for Jak 3!) and intersect with the current texture.
|
||||
if((m_index.tail - 1) == current_tex_end)
|
||||
m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail - m_vertex.head, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM));
|
||||
|
||||
GSVector4i area_out = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(m_context->scissor.in));
|
||||
if (!area_out.rintersect(tex_rect).rempty())
|
||||
// Make sure the format matches, otherwise the coordinates aren't gonna match, so the draws won't intersect.
|
||||
if (GSUtil::HasCompatibleBits(m_context->TEX0.PSM, frame_z_psm) && (m_context->FRAME.FBW == m_context->TEX0.TBW))
|
||||
{
|
||||
Flush();
|
||||
// Update the vertex trace, scissor it (important for Jak 3!) and intersect with the current texture.
|
||||
if ((m_index.tail - 1) == current_tex_end)
|
||||
m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail - m_vertex.head, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM));
|
||||
|
||||
// Intersect goes on space inside the rect
|
||||
GSVector4i area_out = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)) + GSVector4i(0, 0, 1, 1);
|
||||
// Scissor output
|
||||
area_out = area_out.rintersect(GSVector4i(m_context->scissor.in));
|
||||
// Intersect with texture
|
||||
if (!area_out.rintersect(tex_rect).rempty())
|
||||
Flush();
|
||||
}
|
||||
else // Storage of the TEX and FRAME/Z is different, so uhh, just fall back to flushing each page. It's slower, sorry.
|
||||
{
|
||||
|
||||
if (m_context->FRAME.FBW == m_context->TEX0.TBW)
|
||||
{
|
||||
//We know we've changed page, so let's set the dimension to cover the page they're in (for different pixel orders)
|
||||
tex_rect = tex_rect & page_mask;
|
||||
tex_rect += GSVector4i(0, 0, 1, 1); // Intersect goes on space inside the rect
|
||||
tex_rect.z += GSLocalMemory::m_psm[m_context->TEX0.PSM].pgs.x;
|
||||
tex_rect.w += GSLocalMemory::m_psm[m_context->TEX0.PSM].pgs.y;
|
||||
|
||||
if ((m_index.tail - 1) == current_tex_end)
|
||||
m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail - m_vertex.head, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM));
|
||||
|
||||
GSVector4i area_out = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(m_context->scissor.in));
|
||||
area_out = area_out & page_mask;
|
||||
area_out += GSVector4i(0, 0, 1, 1); // Intersect goes on space inside the rect
|
||||
area_out.z += GSLocalMemory::m_psm[m_context->TEX0.PSM].pgs.x;
|
||||
area_out.w += GSLocalMemory::m_psm[m_context->TEX0.PSM].pgs.y;
|
||||
|
||||
if (!area_out.rintersect(tex_rect).rempty())
|
||||
Flush();
|
||||
}
|
||||
else // Page width is different, so it's much more difficult to calculate where it's modifying.
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2534,29 +2715,19 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
switch (prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
case GS_INVALID:
|
||||
n = 1;
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
n = 2;
|
||||
break;
|
||||
case GS_SPRITE:
|
||||
case GS_LINESTRIP:
|
||||
n = 2;
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
n = 3;
|
||||
break;
|
||||
case GS_TRIANGLESTRIP:
|
||||
n = 3;
|
||||
break;
|
||||
case GS_TRIANGLEFAN:
|
||||
n = 3;
|
||||
break;
|
||||
case GS_SPRITE:
|
||||
n = 2;
|
||||
break;
|
||||
case GS_INVALID:
|
||||
n = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_context->FRAME.FBMSK != 0xFFFFFFFF)
|
||||
@@ -2768,9 +2939,6 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
if (PRIM->TME)
|
||||
tex_flushed = false;
|
||||
}
|
||||
|
||||
/// Checks if region repeat is used (applying it does something to at least one of the values in min...max)
|
||||
@@ -3074,8 +3242,9 @@ bool GSState::TryAlphaTest(u32& fm, u32& zm)
|
||||
}
|
||||
else
|
||||
{
|
||||
const int amin = GetAlphaMinMax().min;
|
||||
const int amax = GetAlphaMinMax().max;
|
||||
const GSVertexTrace::VertexAlpha& aminmax = GetAlphaMinMax();
|
||||
const int amin = aminmax.min;
|
||||
const int amax = aminmax.max;
|
||||
|
||||
const int aref = m_context->TEST.AREF;
|
||||
|
||||
@@ -3201,7 +3370,7 @@ bool GSState::IsOpaque()
|
||||
|
||||
bool GSState::IsMipMapDraw()
|
||||
{
|
||||
return m_context->TEX1.MXL > 0 && m_context->TEX1.MMIN >= 2 && m_context->TEX1.MMIN <= 5 && m_vt.m_lod.y > 0 && (!m_context->TEX1.MTBA || m_context->TEX0.TH == m_context->TEX0.TW);
|
||||
return m_context->TEX1.MXL > 0 && m_context->TEX1.MMIN >= 2 && m_context->TEX1.MMIN <= 5 && m_vt.m_lod.y > 0;
|
||||
}
|
||||
|
||||
bool GSState::IsMipMapActive()
|
||||
|
||||
+7
-4
@@ -123,7 +123,7 @@ class GSState : public GSAlignedClass<32>
|
||||
template<bool auto_flush, bool index_swap>
|
||||
void SetPrimHandlers();
|
||||
|
||||
int m_version;
|
||||
u32 m_version;
|
||||
int m_sssize;
|
||||
|
||||
struct GSTransferBuffer
|
||||
@@ -149,14 +149,11 @@ protected:
|
||||
bool IsBadFrame();
|
||||
void SetupCrcHack();
|
||||
|
||||
bool m_userhacks_wildhack;
|
||||
bool m_isPackedUV_HackFlag;
|
||||
CRCHackLevel m_crc_hack_level;
|
||||
GetSkipCount m_gsc;
|
||||
int m_skip;
|
||||
int m_skip_offset;
|
||||
bool m_userhacks_auto_flush;
|
||||
bool tex_flushed;
|
||||
|
||||
GSVertex m_v;
|
||||
float m_q;
|
||||
@@ -164,6 +161,7 @@ protected:
|
||||
GSVector4i m_ofxy;
|
||||
|
||||
bool m_scanmask_used;
|
||||
bool tex_flushed;
|
||||
|
||||
struct
|
||||
{
|
||||
@@ -245,6 +243,8 @@ public:
|
||||
int s_savel;
|
||||
std::string m_dump_root;
|
||||
|
||||
static constexpr u32 STATE_VERSION = 8;
|
||||
|
||||
enum PRIM_OVERLAP
|
||||
{
|
||||
PRIM_OVERLAP_UNKNOW,
|
||||
@@ -273,6 +273,8 @@ public:
|
||||
float GetTvRefreshRate();
|
||||
|
||||
virtual void Reset();
|
||||
virtual void UpdateSettings(const Pcsx2Config::GSOptions& old_config);
|
||||
|
||||
void Flush();
|
||||
void FlushPrim();
|
||||
void FlushWrite();
|
||||
@@ -301,6 +303,7 @@ public:
|
||||
void SetRegsMem(u8* basemem) { m_regs = reinterpret_cast<GSPrivRegSet*>(basemem); }
|
||||
|
||||
void SetFrameSkip(int skip);
|
||||
void DumpVertices(const std::string& filename);
|
||||
|
||||
PRIM_OVERLAP PrimitiveOverlap();
|
||||
GIFRegTEX0 GetTex0Layer(u32 lod);
|
||||
|
||||
@@ -27,7 +27,9 @@ class GSJobQueue final
|
||||
{
|
||||
private:
|
||||
std::thread m_thread;
|
||||
std::function<void()> m_startup;
|
||||
std::function<void(T&)> m_func;
|
||||
std::function<void()> m_shutdown;
|
||||
bool m_exit;
|
||||
ringbuffer_base<T, CAPACITY> m_queue;
|
||||
|
||||
@@ -38,6 +40,9 @@ private:
|
||||
|
||||
void ThreadProc()
|
||||
{
|
||||
if (m_startup)
|
||||
m_startup();
|
||||
|
||||
std::unique_lock<std::mutex> l(m_lock);
|
||||
|
||||
while (true)
|
||||
@@ -74,11 +79,16 @@ private:
|
||||
|
||||
l.lock();
|
||||
}
|
||||
|
||||
if (m_shutdown)
|
||||
m_shutdown();
|
||||
}
|
||||
|
||||
public:
|
||||
GSJobQueue(std::function<void(T&)> func)
|
||||
: m_func(func)
|
||||
GSJobQueue(std::function<void()> startup, std::function<void(T&)> func, std::function<void()> shutdown)
|
||||
: m_startup(std::move(startup))
|
||||
, m_func(std::move(func))
|
||||
, m_shutdown(std::move(shutdown))
|
||||
, m_exit(false)
|
||||
{
|
||||
m_thread = std::thread(&GSJobQueue::ThreadProc, this);
|
||||
|
||||
@@ -20,11 +20,36 @@
|
||||
#include "HostDisplay.h"
|
||||
#include "PerformanceMetrics.h"
|
||||
#include "pcsx2/Config.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
#include "gui/AppCoreThread.h"
|
||||
#if defined(__unix__)
|
||||
#include <X11/keysym.h>
|
||||
#endif
|
||||
|
||||
static std::string GetDumpName()
|
||||
{
|
||||
return StringUtil::wxStringToUTF8String(GameInfo::gameName);
|
||||
}
|
||||
static std::string GetDumpSerial()
|
||||
{
|
||||
return StringUtil::wxStringToUTF8String(GameInfo::gameSerial);
|
||||
}
|
||||
#else
|
||||
#include "VMManager.h"
|
||||
|
||||
static std::string GetDumpName()
|
||||
{
|
||||
return VMManager::GetGameName();
|
||||
}
|
||||
static std::string GetDumpSerial()
|
||||
{
|
||||
return VMManager::GetGameSerial();
|
||||
}
|
||||
#endif
|
||||
|
||||
GSRenderer::GSRenderer()
|
||||
: m_shift_key(false)
|
||||
, m_control_key(false)
|
||||
@@ -391,8 +416,6 @@ static GSVector4 CalculateDrawRect(s32 window_width, s32 window_height, s32 text
|
||||
|
||||
void GSRenderer::VSync(u32 field, bool registers_written)
|
||||
{
|
||||
GSPerfMonAutoTimer pmat(&g_perfmon);
|
||||
|
||||
Flush();
|
||||
|
||||
if (s_dump && s_n >= s_saven)
|
||||
@@ -440,6 +463,9 @@ void GSRenderer::VSync(u32 field, bool registers_written)
|
||||
}
|
||||
|
||||
Host::EndPresentFrame();
|
||||
|
||||
if (GSConfig.OsdShowGPU)
|
||||
PerformanceMetrics::OnGPUPresent(Host::GetHostDisplay()->GetAndResetAccumulatedGPUTime());
|
||||
}
|
||||
g_gs_device->RestoreAPIState();
|
||||
|
||||
@@ -454,10 +480,26 @@ void GSRenderer::VSync(u32 field, bool registers_written)
|
||||
fd.data = new u8[fd.size];
|
||||
Freeze(&fd, false);
|
||||
|
||||
// keep the screenshot relatively small so we don't bloat the dump
|
||||
static constexpr u32 DUMP_SCREENSHOT_WIDTH = 640;
|
||||
static constexpr u32 DUMP_SCREENSHOT_HEIGHT = 480;
|
||||
std::vector<u32> screenshot_pixels;
|
||||
SaveSnapshotToMemory(DUMP_SCREENSHOT_WIDTH, DUMP_SCREENSHOT_HEIGHT, &screenshot_pixels);
|
||||
|
||||
if (m_control_key)
|
||||
m_dump = std::unique_ptr<GSDumpBase>(new GSDump(m_snapshot, m_crc, fd, m_regs));
|
||||
{
|
||||
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpUncompressed(m_snapshot, GetDumpSerial(), m_crc,
|
||||
DUMP_SCREENSHOT_WIDTH, DUMP_SCREENSHOT_HEIGHT,
|
||||
screenshot_pixels.empty() ? nullptr : screenshot_pixels.data(),
|
||||
fd, m_regs));
|
||||
}
|
||||
else
|
||||
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpXz(m_snapshot, m_crc, fd, m_regs));
|
||||
{
|
||||
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpXz(m_snapshot, GetDumpSerial(), m_crc,
|
||||
DUMP_SCREENSHOT_WIDTH, DUMP_SCREENSHOT_HEIGHT,
|
||||
screenshot_pixels.empty() ? nullptr : screenshot_pixels.data(),
|
||||
fd, m_regs));
|
||||
}
|
||||
|
||||
delete[] fd.data;
|
||||
}
|
||||
@@ -528,6 +570,18 @@ bool GSRenderer::MakeSnapshot(const std::string& path)
|
||||
}
|
||||
prev_snap = cur_time;
|
||||
}
|
||||
|
||||
// append the game serial and title
|
||||
if (std::string name(GetDumpName()); !name.empty())
|
||||
{
|
||||
FileSystem::SanitizeFileName(name);
|
||||
m_snapshot += format("_%s", name.c_str());
|
||||
}
|
||||
if (std::string serial(GetDumpSerial()); !serial.empty())
|
||||
{
|
||||
FileSystem::SanitizeFileName(serial);
|
||||
m_snapshot += format("_%s", serial.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +600,7 @@ void GSRenderer::EndCapture()
|
||||
|
||||
void GSRenderer::KeyEvent(const HostKeyEvent& e)
|
||||
{
|
||||
#ifndef __APPLE__ // TODO: Add hotkey support on macOS
|
||||
#if !defined(PCSX2_CORE) && !defined(__APPLE__) // TODO: Add hotkey support on macOS
|
||||
#ifdef _WIN32
|
||||
m_shift_key = !!(::GetAsyncKeyState(VK_SHIFT) & 0x8000);
|
||||
m_control_key = !!(::GetAsyncKeyState(VK_CONTROL) & 0x8000);
|
||||
|
||||
@@ -21,13 +21,15 @@
|
||||
|
||||
CONSTINIT const GSVector4 GSVertexTrace::s_minmax = GSVector4::cxpr(FLT_MAX, -FLT_MAX, 0.f, 0.f);
|
||||
|
||||
GSVertexTrace::GSVertexTrace(const GSState* state)
|
||||
GSVertexTrace::GSVertexTrace(const GSState* state, bool provoking_vertex_first)
|
||||
: m_accurate_stq(false), m_state(state), m_primclass(GS_INVALID_CLASS)
|
||||
{
|
||||
memset(&m_alpha, 0, sizeof(m_alpha));
|
||||
|
||||
#define InitUpdate3(P, IIP, TME, FST, COLOR) \
|
||||
m_fmm[COLOR][FST][TME][IIP][P] = &GSVertexTrace::FindMinMax<P, IIP, TME, FST, COLOR>;
|
||||
m_fmm[COLOR][FST][TME][IIP][P] = \
|
||||
provoking_vertex_first ? &GSVertexTrace::FindMinMax<P, IIP, TME, FST, COLOR, true> : \
|
||||
&GSVertexTrace::FindMinMax<P, IIP, TME, FST, COLOR, false>;
|
||||
|
||||
#define InitUpdate2(P, IIP, TME) \
|
||||
InitUpdate3(P, IIP, TME, 0, 0) \
|
||||
@@ -151,7 +153,7 @@ void GSVertexTrace::Update(const void* vertex, const u32* index, int v_count, in
|
||||
}
|
||||
}
|
||||
|
||||
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
|
||||
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color, bool flat_swapped>
|
||||
void GSVertexTrace::FindMinMax(const void* vertex, const u32* index, int count)
|
||||
{
|
||||
const GSDrawingContext* context = m_state->m_context;
|
||||
@@ -283,16 +285,16 @@ void GSVertexTrace::FindMinMax(const void* vertex, const u32* index, int count)
|
||||
int i = 0;
|
||||
for (; i < (count - 3); i += 6)
|
||||
{
|
||||
processVertices(v[index[i + 0]], v[index[i + 3]], false);
|
||||
processVertices(v[index[i + 0]], v[index[i + 3]], flat_swapped);
|
||||
processVertices(v[index[i + 1]], v[index[i + 4]], false);
|
||||
processVertices(v[index[i + 2]], v[index[i + 5]], true);
|
||||
processVertices(v[index[i + 2]], v[index[i + 5]], !flat_swapped);
|
||||
}
|
||||
if (count & 1)
|
||||
{
|
||||
processVertices(v[index[i + 0]], v[index[i + 1]], false);
|
||||
processVertices(v[index[i + 0]], v[index[i + 1]], flat_swapped);
|
||||
// Compiler optimizations go!
|
||||
// (And if they don't, it's only one vertex out of many)
|
||||
processVertices(v[index[i + 2]], v[index[i + 2]], true);
|
||||
processVertices(v[index[i + 2]], v[index[i + 2]], !flat_swapped);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -48,7 +48,7 @@ protected:
|
||||
|
||||
FindMinMaxPtr m_fmm[2][2][2][2][4];
|
||||
|
||||
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
|
||||
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color, bool provoking_vertex_first>
|
||||
void FindMinMax(const void* vertex, const u32* index, int count);
|
||||
|
||||
public:
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
GSVector2 m_lod; // x = min, y = max
|
||||
|
||||
public:
|
||||
GSVertexTrace(const GSState* state);
|
||||
GSVertexTrace(const GSState* state, bool provoking_vertex_first);
|
||||
virtual ~GSVertexTrace() {}
|
||||
|
||||
void Update(const void* vertex, const u32* index, int v_count, int i_count, GS_PRIM_CLASS primclass);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
static bool SupportsTextureFormat(ID3D11Device* dev, DXGI_FORMAT format)
|
||||
{
|
||||
UINT support;
|
||||
if (FAILED(dev->CheckFormatSupport(DXGI_FORMAT_BC1_UNORM, &support)))
|
||||
if (FAILED(dev->CheckFormatSupport(format, &support)))
|
||||
return false;
|
||||
|
||||
return (support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
bool s_nativeres;
|
||||
static CRCHackLevel s_crc_hack_level = CRCHackLevel::Full;
|
||||
|
||||
// hacks
|
||||
#define CRC_Partial (s_crc_hack_level >= CRCHackLevel::Partial)
|
||||
#define CRC_Full (s_crc_hack_level >= CRCHackLevel::Full)
|
||||
@@ -419,7 +418,7 @@ bool GSC_BurnoutGames(const GSFrameInfo& fi, int& skip)
|
||||
// 0x01dc0 01c00(MP) ntsc, 0x01f00 0x01d40(MP) ntsc progressive, 0x02200(MP) pal.
|
||||
// Yellow stripes.
|
||||
// Multiplayer tested only on Takedown.
|
||||
skip = 4;
|
||||
skip = GSConfig.UserHacks_AutoFlush ? 2 : 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1054,7 +1053,7 @@ bool GSState::IsBadFrame()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_skip == 0 && GSConfig.UserHacks && (GSConfig.SkipDraw > 0))
|
||||
if (m_skip == 0 && GSConfig.SkipDrawEnd > 0)
|
||||
{
|
||||
if (fi.TME)
|
||||
{
|
||||
@@ -1062,8 +1061,8 @@ bool GSState::IsBadFrame()
|
||||
// General, often problematic post processing
|
||||
if (GSLocalMemory::m_psm[fi.TPSM].depth || GSUtil::HasSharedBits(fi.FBP, fi.FPSM, fi.TBP0, fi.TPSM))
|
||||
{
|
||||
m_skip_offset = GSConfig.SkipDrawOffset;
|
||||
m_skip = std::max(GSConfig.SkipDraw, m_skip_offset);
|
||||
m_skip_offset = GSConfig.SkipDrawStart;
|
||||
m_skip = GSConfig.SkipDrawEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,8 @@ GSRendererHW::GSRendererHW()
|
||||
, m_height(default_rt_size.y)
|
||||
, m_custom_width(1024)
|
||||
, m_custom_height(1024)
|
||||
, m_userhacks_ts_half_bottom(-1)
|
||||
, m_tc(new GSTextureCache(this))
|
||||
, m_src(nullptr)
|
||||
, m_hw_mipmap(GSConfig.HWMipmap)
|
||||
, m_userhacks_tcoffset(false)
|
||||
, m_userhacks_tcoffset_x(0)
|
||||
, m_userhacks_tcoffset_y(0)
|
||||
@@ -36,30 +34,8 @@ GSRendererHW::GSRendererHW()
|
||||
, m_reset(false)
|
||||
, m_lod(GSVector2i(0, 0))
|
||||
{
|
||||
m_mipmap = (m_hw_mipmap >= HWMipmapLevel::Basic);
|
||||
m_conservative_framebuffer = theApp.GetConfigB("conservative_framebuffer");
|
||||
|
||||
if (theApp.GetConfigB("UserHacks"))
|
||||
{
|
||||
m_userhacks_enabled_gs_mem_clear = !theApp.GetConfigB("UserHacks_Disable_Safe_Features");
|
||||
m_userHacks_enabled_unscale_ptln = !theApp.GetConfigB("UserHacks_Disable_Safe_Features");
|
||||
m_userhacks_align_sprite_X = theApp.GetConfigB("UserHacks_align_sprite_X");
|
||||
m_userHacks_merge_sprite = theApp.GetConfigB("UserHacks_merge_pp_sprite");
|
||||
m_userhacks_ts_half_bottom = theApp.GetConfigI("UserHacks_Half_Bottom_Override");
|
||||
m_userhacks_round_sprite_offset = theApp.GetConfigI("UserHacks_round_sprite_offset");
|
||||
m_userhacks_tcoffset_x = theApp.GetConfigI("UserHacks_TCOffsetX") / -1000.0f;
|
||||
m_userhacks_tcoffset_y = theApp.GetConfigI("UserHacks_TCOffsetY") / -1000.0f;
|
||||
m_userhacks_tcoffset = m_userhacks_tcoffset_x < 0.0f || m_userhacks_tcoffset_y < 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_userhacks_enabled_gs_mem_clear = true;
|
||||
m_userHacks_enabled_unscale_ptln = true;
|
||||
m_userhacks_align_sprite_X = false;
|
||||
m_userHacks_merge_sprite = false;
|
||||
m_userhacks_ts_half_bottom = -1;
|
||||
m_userhacks_round_sprite_offset = 0;
|
||||
}
|
||||
m_mipmap = (GSConfig.HWMipmap >= HWMipmapLevel::Basic);
|
||||
SetTCOffset();
|
||||
|
||||
if (!GSConfig.UpscaleMultiplier) // Custom Resolution
|
||||
{
|
||||
@@ -67,13 +43,6 @@ GSRendererHW::GSRendererHW()
|
||||
m_custom_height = m_height = theApp.GetConfigI("resy");
|
||||
}
|
||||
|
||||
if (GSConfig.UpscaleMultiplier == 1) // hacks are only needed for upscaling issues.
|
||||
{
|
||||
m_userhacks_round_sprite_offset = 0;
|
||||
m_userhacks_align_sprite_X = false;
|
||||
m_userHacks_merge_sprite = false;
|
||||
}
|
||||
|
||||
m_dump_root = root_hw;
|
||||
GSTextureReplacements::Initialize(m_tc);
|
||||
}
|
||||
@@ -127,7 +96,7 @@ void GSRendererHW::SetScaling()
|
||||
//
|
||||
// m_large_framebuffer has been inverted to m_conservative_framebuffer, it isn't an option that benefits being enabled all the time for everyone.
|
||||
int fb_height = 1280;
|
||||
if (m_conservative_framebuffer)
|
||||
if (GSConfig.ConservativeFramebuffer)
|
||||
{
|
||||
fb_height = fb_width < 1024 ? std::max(512, crtc_size.y) : 1024;
|
||||
}
|
||||
@@ -183,6 +152,13 @@ void GSRendererHW::CustomResolutionScaling()
|
||||
printf("Frame buffer size set to %dx%d (%dx%d)\n", scissored_buffer_size.x, scissored_buffer_size.y, m_width, m_height);
|
||||
}
|
||||
|
||||
void GSRendererHW::SetTCOffset()
|
||||
{
|
||||
m_userhacks_tcoffset_x = std::max<s32>(GSConfig.UserHacks_TCOffsetX, 0) / -1000.0f;
|
||||
m_userhacks_tcoffset_y = std::max<s32>(GSConfig.UserHacks_TCOffsetY, 0) / -1000.0f;
|
||||
m_userhacks_tcoffset = m_userhacks_tcoffset_x < 0.0f || m_userhacks_tcoffset_y < 0.0f;
|
||||
}
|
||||
|
||||
GSRendererHW::~GSRendererHW()
|
||||
{
|
||||
delete m_tc;
|
||||
@@ -207,63 +183,6 @@ void GSRendererHW::SetGameCRC(u32 crc, int options)
|
||||
|
||||
m_hacks.SetGameCRC(m_game);
|
||||
|
||||
// Code for Automatic Mipmapping. Relies on game CRCs.
|
||||
m_hw_mipmap = GSConfig.HWMipmap;
|
||||
m_mipmap = (m_hw_mipmap >= HWMipmapLevel::Basic);
|
||||
if (m_hw_mipmap == HWMipmapLevel::Automatic)
|
||||
{
|
||||
switch (CRC::Lookup(crc).title)
|
||||
{
|
||||
case CRC::AceCombatZero:
|
||||
case CRC::AceCombat4:
|
||||
case CRC::AceCombat5:
|
||||
case CRC::ApeEscape2:
|
||||
case CRC::Barnyard:
|
||||
case CRC::BrianLaraInternationalCricket:
|
||||
case CRC::DarkCloud:
|
||||
case CRC::DestroyAllHumans:
|
||||
case CRC::DestroyAllHumans2:
|
||||
case CRC::FIFA03:
|
||||
case CRC::FIFA04:
|
||||
case CRC::FIFA05:
|
||||
case CRC::HarryPotterATCOS:
|
||||
case CRC::HarryPotterATGOF:
|
||||
case CRC::HarryPotterATHBP:
|
||||
case CRC::HarryPotterATPOA:
|
||||
case CRC::HarryPotterOOTP:
|
||||
case CRC::ICO:
|
||||
case CRC::Jak1:
|
||||
case CRC::Jak3:
|
||||
case CRC::JurassicPark:
|
||||
case CRC::LegacyOfKainDefiance:
|
||||
case CRC::NicktoonsUnite:
|
||||
case CRC::Persona3:
|
||||
case CRC::ProjectSnowblind:
|
||||
case CRC::Quake3Revolution:
|
||||
case CRC::RatchetAndClank:
|
||||
case CRC::RatchetAndClank2:
|
||||
case CRC::RatchetAndClank3:
|
||||
case CRC::RatchetAndClank4:
|
||||
case CRC::RatchetAndClank5:
|
||||
case CRC::RickyPontingInternationalCricket:
|
||||
case CRC::Shox:
|
||||
case CRC::SlamTennis:
|
||||
case CRC::SoTC:
|
||||
case CRC::SoulReaver2:
|
||||
case CRC::TheIncredibleHulkUD:
|
||||
case CRC::TombRaiderAnniversary:
|
||||
case CRC::TribesAerialAssault:
|
||||
case CRC::Whiplash:
|
||||
m_hw_mipmap = HWMipmapLevel::Basic;
|
||||
m_mipmap = true;
|
||||
break;
|
||||
default:
|
||||
m_hw_mipmap = HWMipmapLevel::Off;
|
||||
m_mipmap = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GSTextureReplacements::GameChanged();
|
||||
}
|
||||
|
||||
@@ -297,6 +216,13 @@ void GSRendererHW::Reset()
|
||||
GSRenderer::Reset();
|
||||
}
|
||||
|
||||
void GSRendererHW::UpdateSettings(const Pcsx2Config::GSOptions& old_config)
|
||||
{
|
||||
GSRenderer::UpdateSettings(old_config);
|
||||
m_mipmap = (GSConfig.HWMipmap >= HWMipmapLevel::Basic);
|
||||
SetTCOffset();
|
||||
}
|
||||
|
||||
void GSRendererHW::VSync(u32 field, bool registers_written)
|
||||
{
|
||||
if (m_reset)
|
||||
@@ -544,7 +470,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba)
|
||||
read_ba = (tex_pos > 112 && tex_pos < 144);
|
||||
|
||||
bool half_bottom = false;
|
||||
switch (m_userhacks_ts_half_bottom)
|
||||
switch (GSConfig.UserHacks_HalfBottomOverride)
|
||||
{
|
||||
case 0:
|
||||
// Force Disabled.
|
||||
@@ -572,9 +498,30 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba)
|
||||
//
|
||||
// 32bits emulation means we can do the effect once but double the size.
|
||||
// Test cases: Crash Twinsantiy and DBZ BT3
|
||||
const int height_delta = m_src->m_valid_rect.height() - m_r.height();
|
||||
// Test Case: NFS: HP2 splits the effect h:256 and h:192 so 64
|
||||
half_bottom = abs(height_delta) <= 64;
|
||||
// Other games: Midnight Club 3 headlights, black bar in Xenosaga 3 dialogue,
|
||||
// Firefighter FD18 fire occlusion, PSI Ops half screen green overlay, Lord of the Rings - Two Towers,
|
||||
// Demon Stone , Sonic Unleashed, Lord of the Rings Two Towers,
|
||||
// Superman Shadow of Apokolips, Matrix Path of Neo, Big Mutha Truckers
|
||||
|
||||
int maxvert = 0;
|
||||
int minvert = 4096;
|
||||
for (size_t i = 0; i < count; i ++)
|
||||
{
|
||||
int YCord = 0;
|
||||
|
||||
if (!PRIM->FST)
|
||||
YCord = (int)((1 << m_context->TEX0.TH) * (v[i].ST.T / v[i].RGBAQ.Q));
|
||||
else
|
||||
YCord = (v[i].V >> 4);
|
||||
|
||||
if (maxvert < YCord)
|
||||
maxvert = YCord;
|
||||
if (minvert > YCord)
|
||||
minvert = YCord;
|
||||
}
|
||||
|
||||
half_bottom = minvert == 0 && m_r.height() <= maxvert;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -753,7 +700,7 @@ GSVector4i GSRendererHW::ComputeBoundingBox(const GSVector2& rtscale, const GSVe
|
||||
void GSRendererHW::MergeSprite(GSTextureCache::Source* tex)
|
||||
{
|
||||
// Upscaling hack to avoid various line/grid issues
|
||||
if (m_userHacks_merge_sprite && tex && tex->m_target && (m_vt.m_primclass == GS_SPRITE_CLASS))
|
||||
if (GSConfig.UserHacks_MergePPSprite && tex && tex->m_target && (m_vt.m_primclass == GS_SPRITE_CLASS))
|
||||
{
|
||||
if (PRIM->FST && GSLocalMemory::m_psm[tex->m_TEX0.PSM].fmt < 2 && ((m_vt.m_eq.value & 0xCFFFF) == 0xCFFFF))
|
||||
{
|
||||
@@ -1249,6 +1196,20 @@ void GSRendererHW::RoundSpriteOffset()
|
||||
|
||||
void GSRendererHW::Draw()
|
||||
{
|
||||
if (s_dump && (s_n >= s_saven))
|
||||
{
|
||||
std::string s;
|
||||
|
||||
// Dump Register state
|
||||
s = format("%05d_context.txt", s_n);
|
||||
|
||||
m_env.Dump(m_dump_root + s);
|
||||
m_context->Dump(m_dump_root + s);
|
||||
|
||||
// Dump vertices
|
||||
s = format("%05d_vertex.txt", s_n);
|
||||
DumpVertices(m_dump_root + s);
|
||||
}
|
||||
if (IsBadFrame())
|
||||
{
|
||||
GL_INS("Warning skipping a draw call (%d)", s_n);
|
||||
@@ -1424,7 +1385,7 @@ void GSRendererHW::Draw()
|
||||
|
||||
// upload the full chain (with offset) for the hash cache, in case some other texture uses more levels
|
||||
// for basic mipmapping, we can get away with just doing the base image, since all the mips get generated anyway.
|
||||
hash_lod_range = GSVector2i(m_lod.x, (m_hw_mipmap == HWMipmapLevel::Full) ? mxl : m_lod.x);
|
||||
hash_lod_range = GSVector2i(m_lod.x, (GSConfig.HWMipmap == HWMipmapLevel::Full) ? mxl : m_lod.x);
|
||||
|
||||
MIP_CLAMP.MINU >>= m_lod.x;
|
||||
MIP_CLAMP.MINV >>= m_lod.x;
|
||||
@@ -1449,7 +1410,7 @@ void GSRendererHW::Draw()
|
||||
TextureMinMaxResult tmm = GetTextureMinMax(TEX0, MIP_CLAMP, m_vt.IsLinear());
|
||||
|
||||
m_src = tex_psm.depth ? m_tc->LookupDepthSource(TEX0, env.TEXA, tmm.coverage) :
|
||||
m_tc->LookupSource(TEX0, env.TEXA, tmm.coverage, (m_hw_mipmap >= HWMipmapLevel::Basic ||
|
||||
m_tc->LookupSource(TEX0, env.TEXA, tmm.coverage, (GSConfig.HWMipmap >= HWMipmapLevel::Basic ||
|
||||
GSConfig.UserHacks_TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr);
|
||||
|
||||
int tw = 1 << TEX0.TW;
|
||||
@@ -1504,7 +1465,7 @@ void GSRendererHW::Draw()
|
||||
}
|
||||
|
||||
// Round 2
|
||||
if (IsMipMapActive() && m_hw_mipmap == HWMipmapLevel::Full && !tex_psm.depth && !m_src->m_from_hash_cache)
|
||||
if (IsMipMapActive() && GSConfig.HWMipmap == HWMipmapLevel::Full && !tex_psm.depth && !m_src->m_from_hash_cache)
|
||||
{
|
||||
// Upload remaining texture layers
|
||||
const GSVector4 tmin = m_vt.m_min.t;
|
||||
@@ -1655,15 +1616,6 @@ void GSRendererHW::Draw()
|
||||
|
||||
std::string s;
|
||||
|
||||
if (s_n >= s_saven)
|
||||
{
|
||||
// Dump Register state
|
||||
s = format("%05d_context.txt", s_n);
|
||||
|
||||
m_env.Dump(m_dump_root + s);
|
||||
m_context->Dump(m_dump_root + s);
|
||||
}
|
||||
|
||||
if (s_savet && s_n >= s_saven && m_src)
|
||||
{
|
||||
s = format("%05d_f%lld_itex_%05x_%s_%d%d_%02x_%02x_%02x_%02x.dds",
|
||||
@@ -1711,7 +1663,7 @@ void GSRendererHW::Draw()
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_userhacks_enabled_gs_mem_clear)
|
||||
if (!GSConfig.UserHacks_DisableSafeFeatures)
|
||||
{
|
||||
// Constant Direct Write without texture/test/blending (aka a GS mem clear)
|
||||
if ((m_vt.m_primclass == GS_SPRITE_CLASS) && !PRIM->TME // Direct write
|
||||
@@ -1737,7 +1689,7 @@ void GSRendererHW::Draw()
|
||||
GSVertex* v = &m_vertex.buff[0];
|
||||
|
||||
// Hack to avoid vertical black line in various games (ace combat/tekken)
|
||||
if (m_userhacks_align_sprite_X)
|
||||
if (GSConfig.UserHacks_AlignSpriteX)
|
||||
{
|
||||
// Note for performance reason I do the check only once on the first
|
||||
// primitive
|
||||
@@ -1763,7 +1715,7 @@ void GSRendererHW::Draw()
|
||||
// Noting to do if no texture is sampled
|
||||
if (PRIM->FST && draw_sprite_tex)
|
||||
{
|
||||
if ((m_userhacks_round_sprite_offset > 1) || (m_userhacks_round_sprite_offset == 1 && !m_vt.IsLinear()))
|
||||
if ((GSConfig.UserHacks_RoundSprite > 1) || (GSConfig.UserHacks_RoundSprite == 1 && !m_vt.IsLinear()))
|
||||
{
|
||||
if (m_vt.IsLinear())
|
||||
RoundSpriteOffset<true>();
|
||||
@@ -1888,9 +1840,10 @@ void GSRendererHW::Hacks::SetGameCRC(const CRC::Game& game)
|
||||
m_oo = m_oo_map[hash];
|
||||
m_cu = m_cu_map[hash];
|
||||
|
||||
if (game.flags & CRC::PointListPalette)
|
||||
if (GSConfig.PointListPalette)
|
||||
{
|
||||
ASSERT(m_oi == NULL);
|
||||
if (m_oi)
|
||||
Console.Warning("Overriding m_oi with PointListPalette");
|
||||
|
||||
m_oi = &GSRendererHW::OI_PointListPalette;
|
||||
}
|
||||
|
||||
@@ -27,12 +27,6 @@ private:
|
||||
int m_height;
|
||||
int m_custom_width;
|
||||
int m_custom_height;
|
||||
int m_userhacks_ts_half_bottom;
|
||||
|
||||
bool m_conservative_framebuffer;
|
||||
bool m_userhacks_align_sprite_X;
|
||||
bool m_userhacks_enabled_gs_mem_clear;
|
||||
bool m_userHacks_merge_sprite;
|
||||
|
||||
static constexpr float SSR_UV_TOLERANCE = 1.0f;
|
||||
|
||||
@@ -144,12 +138,10 @@ protected:
|
||||
GSTextureCache* m_tc;
|
||||
GSVector4i m_r;
|
||||
GSTextureCache::Source* m_src;
|
||||
HWMipmapLevel m_hw_mipmap;
|
||||
|
||||
virtual void DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex) = 0;
|
||||
|
||||
int m_userhacks_round_sprite_offset;
|
||||
bool m_userHacks_enabled_unscale_ptln;
|
||||
void SetTCOffset();
|
||||
|
||||
bool m_userhacks_tcoffset;
|
||||
float m_userhacks_tcoffset_x;
|
||||
@@ -185,6 +177,7 @@ public:
|
||||
GSVector2i GetTargetSize();
|
||||
|
||||
void Reset() override;
|
||||
void UpdateSettings(const Pcsx2Config::GSOptions& old_config) override;
|
||||
void VSync(u32 field, bool registers_written) override;
|
||||
|
||||
GSTexture* GetOutput(int i, int& y_offset) override;
|
||||
|
||||
@@ -33,12 +33,12 @@ void GSRendererNew::SetupIA(const float& sx, const float& sy)
|
||||
{
|
||||
GL_PUSH("IA");
|
||||
|
||||
if (m_userhacks_wildhack && !m_isPackedUV_HackFlag && PRIM->TME && PRIM->FST)
|
||||
if (GSConfig.UserHacks_WildHack && !m_isPackedUV_HackFlag && PRIM->TME && PRIM->FST)
|
||||
{
|
||||
for (unsigned int i = 0; i < m_vertex.next; i++)
|
||||
m_vertex.buff[i].UV &= 0x3FEF3FEF;
|
||||
}
|
||||
const bool unscale_pt_ln = m_userHacks_enabled_unscale_ptln && (GetUpscaleMultiplier() != 1);
|
||||
const bool unscale_pt_ln = !GSConfig.UserHacks_DisableSafeFeatures && (GetUpscaleMultiplier() != 1);
|
||||
const GSDevice::FeatureSupport features = g_gs_device->Features();
|
||||
|
||||
switch (m_vt.m_primclass)
|
||||
@@ -540,23 +540,68 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
|
||||
// Compute the blending equation to detect special case
|
||||
const GIFRegALPHA& ALPHA = m_context->ALPHA;
|
||||
|
||||
// Set blending to shader bits
|
||||
m_conf.ps.blend_a = ALPHA.A;
|
||||
m_conf.ps.blend_b = ALPHA.B;
|
||||
m_conf.ps.blend_c = ALPHA.C;
|
||||
m_conf.ps.blend_d = ALPHA.D;
|
||||
|
||||
// Get alpha value
|
||||
const bool alpha_c0_zero = (m_conf.ps.blend_c == 0 && GetAlphaMinMax().max == 0);
|
||||
const bool alpha_c0_one = (m_conf.ps.blend_c == 0 && (GetAlphaMinMax().min == 128) && (GetAlphaMinMax().max == 128));
|
||||
const bool alpha_c0_high_max_one = (m_conf.ps.blend_c == 0 && GetAlphaMinMax().max > 128);
|
||||
const bool alpha_c2_zero = (m_conf.ps.blend_c == 2 && ALPHA.FIX == 0u);
|
||||
const bool alpha_c2_one = (m_conf.ps.blend_c == 2 && ALPHA.FIX == 128u);
|
||||
const bool alpha_c2_high_one = (m_conf.ps.blend_c == 2 && ALPHA.FIX > 128u);
|
||||
|
||||
// Optimize blending equations, must be done before index calculation
|
||||
if ((m_conf.ps.blend_a == m_conf.ps.blend_b) || ((m_conf.ps.blend_b == m_conf.ps.blend_d) && (alpha_c0_one || alpha_c2_one)))
|
||||
{
|
||||
// Condition 1:
|
||||
// A == B
|
||||
// (A - B) * C, result will be 0.0f so set A B to Cs, C to As
|
||||
// Condition 2:
|
||||
// B == D
|
||||
// Swap D with A
|
||||
// A == B
|
||||
// (A - B) * C, result will be 0.0f so set A B to Cs, C to As
|
||||
if (m_conf.ps.blend_a != m_conf.ps.blend_b)
|
||||
m_conf.ps.blend_d = m_conf.ps.blend_a;
|
||||
m_conf.ps.blend_a = 0;
|
||||
m_conf.ps.blend_b = 0;
|
||||
m_conf.ps.blend_c = 0;
|
||||
}
|
||||
else if (alpha_c0_zero || alpha_c2_zero)
|
||||
{
|
||||
// C == 0.0f
|
||||
// (A - B) * C, result will be 0.0f so set A B to Cs
|
||||
m_conf.ps.blend_a = 0;
|
||||
m_conf.ps.blend_b = 0;
|
||||
}
|
||||
|
||||
// Ad cases, alpha write is masked, one barrier is enough, for d3d11 read the fb
|
||||
// Replace Ad with As, blend flags will be used from As since we are chaging the blend_index value.
|
||||
bool blend_ad_alpha_masked = (ALPHA.C == 1) && (m_context->FRAME.FBMSK & 0xFF000000) == 0xFF000000;
|
||||
u8 ALPHA_C = ALPHA.C;
|
||||
if (g_gs_device->Features().texture_barrier && blend_ad_alpha_masked)
|
||||
ALPHA_C = 0;
|
||||
// Must be done before index calculation, after blending equation optimizations
|
||||
bool blend_ad_alpha_masked = (m_conf.ps.blend_c == 1) && (m_context->FRAME.FBMSK & 0xFF000000) == 0xFF000000;
|
||||
if (((GSConfig.AccurateBlendingUnit >= AccBlendLevel::Basic) || (m_env.COLCLAMP.CLAMP == 0))
|
||||
&& g_gs_device->Features().texture_barrier && blend_ad_alpha_masked)
|
||||
m_conf.ps.blend_c = 0;
|
||||
else if (((GSConfig.AccurateBlendingUnit >= AccBlendLevel::Medium)
|
||||
// Detect barrier aka fbmask on d3d11.
|
||||
|| m_conf.require_one_barrier)
|
||||
&& blend_ad_alpha_masked)
|
||||
ALPHA_C = 0;
|
||||
m_conf.ps.blend_c = 0;
|
||||
else
|
||||
blend_ad_alpha_masked = false;
|
||||
|
||||
u8 blend_index = u8(((ALPHA.A * 3 + ALPHA.B) * 3 + ALPHA_C) * 3 + ALPHA.D);
|
||||
u8 blend_index = u8(((m_conf.ps.blend_a * 3 + m_conf.ps.blend_b) * 3 + m_conf.ps.blend_c) * 3 + m_conf.ps.blend_d);
|
||||
const int blend_flag = g_gs_device->GetBlendFlags(blend_index);
|
||||
|
||||
// Re set alpha, it was modified, must be done after index calculation
|
||||
if (blend_ad_alpha_masked)
|
||||
m_conf.ps.blend_c = ALPHA.C;
|
||||
|
||||
// HW blend can handle Cd output.
|
||||
bool color_dest_blend = !!(blend_flag & BLEND_CD);
|
||||
|
||||
@@ -572,15 +617,12 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
const bool blend_mix3 = !!(blend_flag & BLEND_MIX3);
|
||||
bool blend_mix = (blend_mix1 || blend_mix2 || blend_mix3);
|
||||
|
||||
const bool alpha_c2_high_one = (ALPHA.C == 2 && ALPHA.FIX > 128u);
|
||||
const bool alpha_c0_high_max_one = (ALPHA.C == 0 && GetAlphaMinMax().max > 128);
|
||||
|
||||
// Blend can be done on hw. As and F cases should be accurate.
|
||||
// BLEND_C_CLR1 with Ad, BLEND_C_CLR3 Cs > 0.5f will require sw blend.
|
||||
// BLEND_C_CLR1 with As/F, BLEND_C_CLR2_AF, BLEND_C_CLR2_AS can be done in hw.
|
||||
const bool clr_blend = !!(blend_flag & (BLEND_C_CLR1 | BLEND_C_CLR2_AF | BLEND_C_CLR2_AS | BLEND_C_CLR3));
|
||||
bool clr_blend1_2 = (blend_flag & (BLEND_C_CLR1 | BLEND_C_CLR2_AF | BLEND_C_CLR2_AS))
|
||||
&& (ALPHA.C != 1) // Make sure it isn't an Ad case
|
||||
&& (m_conf.ps.blend_c != 1) // Make sure it isn't an Ad case
|
||||
&& !m_env.PABE.PABE // No PABE as it will require sw blending.
|
||||
&& (m_env.COLCLAMP.CLAMP) // Let's add a colclamp check too, hw blend will clamp to 0-1.
|
||||
&& !(m_conf.require_one_barrier || m_conf.require_full_barrier); // Also don't run if there are barriers present.
|
||||
@@ -608,10 +650,10 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
sw_blending |= true;
|
||||
[[fallthrough]];
|
||||
case AccBlendLevel::Full:
|
||||
sw_blending |= ALPHA.A != ALPHA.B && alpha_c0_high_max_one;
|
||||
sw_blending |= m_conf.ps.blend_a != m_conf.ps.blend_b && alpha_c0_high_max_one;
|
||||
[[fallthrough]];
|
||||
case AccBlendLevel::High:
|
||||
sw_blending |= ALPHA.C == 1 || (ALPHA.A != ALPHA.B && alpha_c2_high_one);
|
||||
sw_blending |= m_conf.ps.blend_c == 1 || (m_conf.ps.blend_a != m_conf.ps.blend_b && alpha_c2_high_one);
|
||||
[[fallthrough]];
|
||||
case AccBlendLevel::Medium:
|
||||
// Initial idea was to enable accurate blending for sprite rendering to handle
|
||||
@@ -654,7 +696,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
}
|
||||
[[fallthrough]];
|
||||
case AccBlendLevel::Full:
|
||||
sw_blending |= ((ALPHA.C == 1 || (blend_mix && (alpha_c2_high_one || alpha_c0_high_max_one))) && (m_prim_overlap == PRIM_OVERLAP_NO));
|
||||
sw_blending |= ((m_conf.ps.blend_c == 1 || (blend_mix && (alpha_c2_high_one || alpha_c0_high_max_one))) && (m_prim_overlap == PRIM_OVERLAP_NO));
|
||||
[[fallthrough]];
|
||||
case AccBlendLevel::High:
|
||||
sw_blending |= (!(clr_blend || blend_mix) && (m_prim_overlap == PRIM_OVERLAP_NO));
|
||||
@@ -694,7 +736,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
else
|
||||
free_colclip = blend_non_recursive;
|
||||
|
||||
GL_DBG("COLCLIP Info (Blending: %u/%u/%u/%u, OVERLAP: %d)", ALPHA.A, ALPHA.B, ALPHA.C, ALPHA.D, m_prim_overlap);
|
||||
GL_DBG("COLCLIP Info (Blending: %u/%u/%u/%u, OVERLAP: %d)", m_conf.ps.blend_a, m_conf.ps.blend_b, m_conf.ps.blend_c, m_conf.ps.blend_d, m_prim_overlap);
|
||||
if (color_dest_blend)
|
||||
{
|
||||
// No overflow, disable colclip.
|
||||
@@ -758,7 +800,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
m_conf.ps.pabe = !(accumulation_blend || blend_mix);
|
||||
}
|
||||
}
|
||||
else if (ALPHA.A == 0 && ALPHA.B == 1 && ALPHA.C == 0 && ALPHA.D == 1)
|
||||
else if (m_conf.ps.blend_a == 0 && m_conf.ps.blend_b == 1 && m_conf.ps.blend_c == 0 && m_conf.ps.blend_d == 1)
|
||||
{
|
||||
// this works because with PABE alpha blending is on when alpha >= 0x80, but since the pixel shader
|
||||
// cannot output anything over 0x80 (== 1.0) blending with 0x80 or turning it off gives the same result
|
||||
@@ -769,7 +811,8 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
// For stat to optimize accurate option
|
||||
#if 0
|
||||
GL_INS("BLEND_INFO: %u/%u/%u/%u. Clamp:%u. Prim:%d number %u (drawlist %u) (sw %d)",
|
||||
ALPHA.A, ALPHA.B, ALPHA.C, ALPHA.D, m_env.COLCLAMP.CLAMP, m_vt.m_primclass, m_vertex.next, m_drawlist.size(), sw_blending);
|
||||
m_conf.ps.blend_a, m_conf.ps.blend_b, m_conf.ps.blend_c, m_conf.ps.blend_d,
|
||||
m_env.COLCLAMP.CLAMP, m_vt.m_primclass, m_vertex.next, m_drawlist.size(), sw_blending);
|
||||
#endif
|
||||
if (color_dest_blend)
|
||||
{
|
||||
@@ -784,24 +827,9 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
}
|
||||
else if (sw_blending)
|
||||
{
|
||||
m_conf.ps.blend_a = ALPHA.A;
|
||||
m_conf.ps.blend_b = ALPHA.B;
|
||||
m_conf.ps.blend_c = ALPHA.C;
|
||||
m_conf.ps.blend_d = ALPHA.D;
|
||||
|
||||
if (m_conf.ps.blend_a == m_conf.ps.blend_b)
|
||||
{
|
||||
// A == B
|
||||
// (A - B) * C will be 0 so set A B to Cs, C to As
|
||||
m_conf.ps.blend_a = 0;
|
||||
m_conf.ps.blend_b = 0;
|
||||
m_conf.ps.blend_c = 0;
|
||||
}
|
||||
else if (m_conf.ps.blend_c == 2)
|
||||
{
|
||||
// Require the fix alpha vlaue
|
||||
// Require the fix alpha vlaue
|
||||
if (m_conf.ps.blend_c == 2)
|
||||
m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast<float>(ALPHA.FIX) / 128.0f;
|
||||
}
|
||||
|
||||
if (accumulation_blend)
|
||||
{
|
||||
@@ -869,8 +897,12 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Care for clr_hw value, 6 is for hw/sw, sw blending used.
|
||||
// No sw blending
|
||||
m_conf.ps.blend_a = 0;
|
||||
m_conf.ps.blend_b = 0;
|
||||
m_conf.ps.blend_d = 0;
|
||||
|
||||
// Care for clr_hw value, 6 is for hw/sw, sw blending used.
|
||||
if (blend_flag & BLEND_C_CLR1)
|
||||
{
|
||||
if (blend_ad_alpha_masked)
|
||||
@@ -892,13 +924,13 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
m_conf.ps.clr_hw = 4;
|
||||
m_conf.require_one_barrier |= true;
|
||||
}
|
||||
else if (ALPHA.C == 2)
|
||||
else if (m_conf.ps.blend_c == 2)
|
||||
{
|
||||
m_conf.ps.blend_c = 2;
|
||||
m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast<float>(ALPHA.FIX) / 128.0f;
|
||||
m_conf.ps.clr_hw = 2;
|
||||
}
|
||||
else // ALPHA.C == 0
|
||||
else // m_conf.ps.blend_c == 0
|
||||
{
|
||||
m_conf.ps.blend_c = 0;
|
||||
m_conf.ps.clr_hw = 2;
|
||||
@@ -915,7 +947,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
m_conf.require_one_barrier |= true;
|
||||
}
|
||||
|
||||
if (m_conf.ps.dfmt == 1 && ALPHA.C == 1)
|
||||
if (m_conf.ps.dfmt == 1 && m_conf.ps.blend_c == 1)
|
||||
{
|
||||
// 24 bits doesn't have an alpha channel so use 1.0f fix factor as equivalent
|
||||
const u8 hacked_blend_index = blend_index + 3; // +3 <=> +1 on C
|
||||
@@ -923,7 +955,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_conf.blend = {blend_index, ALPHA.FIX, ALPHA.C == 2, false, false};
|
||||
m_conf.blend = {blend_index, ALPHA.FIX, m_conf.ps.blend_c == 2, false, false};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -955,7 +987,7 @@ void GSRendererNew::EmulateTextureSampler(const GSTextureCache::Source* tex)
|
||||
|
||||
const bool need_mipmap = IsMipMapDraw();
|
||||
const bool shader_emulated_sampler = tex->m_palette || cpsm.fmt != 0 || complex_wms_wmt || psm.depth;
|
||||
const bool trilinear_manual = need_mipmap && m_hw_mipmap == HWMipmapLevel::Full;
|
||||
const bool trilinear_manual = need_mipmap && GSConfig.HWMipmap == HWMipmapLevel::Full;
|
||||
|
||||
bool bilinear = m_vt.IsLinear();
|
||||
int trilinear = 0;
|
||||
@@ -964,11 +996,11 @@ void GSRendererNew::EmulateTextureSampler(const GSTextureCache::Source* tex)
|
||||
{
|
||||
case TriFiltering::Forced:
|
||||
trilinear = static_cast<u8>(GS_MIN_FILTER::Linear_Mipmap_Linear);
|
||||
trilinear_auto = !need_mipmap || m_hw_mipmap != HWMipmapLevel::Full;
|
||||
trilinear_auto = !need_mipmap || GSConfig.HWMipmap != HWMipmapLevel::Full;
|
||||
break;
|
||||
|
||||
case TriFiltering::PS2:
|
||||
if (need_mipmap && m_hw_mipmap != HWMipmapLevel::Full)
|
||||
if (need_mipmap && GSConfig.HWMipmap != HWMipmapLevel::Full)
|
||||
{
|
||||
trilinear = m_context->TEX1.MMIN;
|
||||
trilinear_auto = true;
|
||||
|
||||
@@ -27,35 +27,12 @@
|
||||
#define XXH_INLINE_ALL 1
|
||||
#include "xxhash.h"
|
||||
|
||||
bool GSTextureCache::m_disable_partial_invalidation = false;
|
||||
bool GSTextureCache::m_wrap_gs_mem = false;
|
||||
u8* GSTextureCache::m_temp;
|
||||
|
||||
GSTextureCache::GSTextureCache(GSRenderer* r)
|
||||
: m_renderer(r)
|
||||
, m_palette_map(r)
|
||||
{
|
||||
if (theApp.GetConfigB("UserHacks"))
|
||||
{
|
||||
UserHacks_HalfPixelOffset = theApp.GetConfigI("UserHacks_HalfPixelOffset") == 1;
|
||||
m_preload_frame = theApp.GetConfigB("preload_frame_with_gs_data");
|
||||
m_disable_partial_invalidation = theApp.GetConfigB("UserHacks_DisablePartialInvalidation");
|
||||
m_can_convert_depth = !theApp.GetConfigB("UserHacks_DisableDepthSupport");
|
||||
m_cpu_fb_conversion = theApp.GetConfigB("UserHacks_CPU_FB_Conversion");
|
||||
m_texture_inside_rt = theApp.GetConfigB("UserHacks_TextureInsideRt");
|
||||
m_wrap_gs_mem = theApp.GetConfigB("wrap_gs_mem");
|
||||
}
|
||||
else
|
||||
{
|
||||
UserHacks_HalfPixelOffset = false;
|
||||
m_preload_frame = false;
|
||||
m_disable_partial_invalidation = false;
|
||||
m_can_convert_depth = true;
|
||||
m_cpu_fb_conversion = false;
|
||||
m_texture_inside_rt = false;
|
||||
m_wrap_gs_mem = false;
|
||||
}
|
||||
|
||||
// In theory 4MB is enough but 9MB is safer for overflow (8MB
|
||||
// isn't enough in custom resolution)
|
||||
// Test: onimusha 3 PAL 60Hz
|
||||
@@ -110,7 +87,7 @@ void GSTextureCache::RemoveAll()
|
||||
|
||||
GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, bool palette)
|
||||
{
|
||||
if (!m_can_convert_depth)
|
||||
if (GSConfig.UserHacks_DisableDepthSupport)
|
||||
{
|
||||
GL_CACHE("LookupDepthSource not supported (0x%x, F:0x%x)", TEX0.TBP0, TEX0.PSM);
|
||||
throw GSRecoverableError();
|
||||
@@ -280,8 +257,6 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||
// (Simply not doing this code at all makes a lot of previsouly missing stuff show (but breaks pretty much everything
|
||||
// else.)
|
||||
|
||||
const bool texture_inside_rt = ShallSearchTextureInsideRt();
|
||||
|
||||
bool found_t = false;
|
||||
for (auto t : m_dst[RenderTarget])
|
||||
{
|
||||
@@ -305,7 +280,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||
// 1/ it just works :)
|
||||
// 2/ even with upscaling
|
||||
// 3/ for both Direct3D and OpenGL
|
||||
if (m_cpu_fb_conversion && (psm == PSM_PSMT4 || psm == PSM_PSMT8))
|
||||
if (GSConfig.UserHacks_CPUFBConversion && (psm == PSM_PSMT4 || psm == PSM_PSMT8))
|
||||
// Forces 4-bit and 8-bit frame buffer conversion to be done on the CPU instead of the GPU, but performance will be slower.
|
||||
// There is no dedicated shader to handle 4-bit conversion (Stuntman has been confirmed to use 4-bit).
|
||||
// Direct3D10/11 and OpenGL support 8-bit fb conversion but don't render some corner cases properly (Harry Potter games).
|
||||
@@ -326,7 +301,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||
found_t = true;
|
||||
break;
|
||||
}
|
||||
else if (texture_inside_rt && psm == PSM_PSMCT32 && t->m_TEX0.PSM == psm &&
|
||||
else if (GSConfig.UserHacks_TextureInsideRt && psm == PSM_PSMCT32 && t->m_TEX0.PSM == psm &&
|
||||
((t->m_TEX0.TBP0 < bp && t->m_end_block >= bp) || t_wraps))
|
||||
{
|
||||
// Only PSMCT32 to limit false hits.
|
||||
@@ -366,7 +341,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||
//
|
||||
// Sigh... They don't help us.
|
||||
|
||||
if (!found_t && m_can_convert_depth)
|
||||
if (!found_t && !GSConfig.UserHacks_DisableDepthSupport)
|
||||
{
|
||||
// Let's try a trick to avoid to use wrongly a depth buffer
|
||||
// Unfortunately, I don't have any Arc the Lad testcase
|
||||
@@ -439,11 +414,6 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||
return src;
|
||||
}
|
||||
|
||||
bool GSTextureCache::ShallSearchTextureInsideRt()
|
||||
{
|
||||
return m_texture_inside_rt || (m_renderer->m_game.flags & CRC::Flags::TextureInsideRt);
|
||||
}
|
||||
|
||||
GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask, const bool is_frame, const int real_h)
|
||||
{
|
||||
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
|
||||
@@ -545,7 +515,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
|
||||
if (!is_frame)
|
||||
dst->m_dirty_alpha |= (psm_s.trbpp == 32 && (fbmask & 0xFF000000) != 0xFF000000) || (psm_s.trbpp == 16);
|
||||
}
|
||||
else if (!is_frame && m_can_convert_depth)
|
||||
else if (!is_frame && !GSConfig.UserHacks_DisableDepthSupport)
|
||||
{
|
||||
|
||||
int rev_type = (type == DepthStencil) ? RenderTarget : DepthStencil;
|
||||
@@ -576,7 +546,9 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
|
||||
dst = CreateTarget(TEX0, new_size.x, new_size.y, type, clear);
|
||||
dst->m_32_bits_fmt = dst_match->m_32_bits_fmt;
|
||||
ShaderConvert shader;
|
||||
bool fmt_16_bits = (psm_s.bpp == 16 && GSLocalMemory::m_psm[dst_match->m_TEX0.PSM].bpp == 16);
|
||||
// m_32_bits_fmt gets set on a shuffle or if the format isn't 16bit.
|
||||
// In this case it needs to make sure it isn't part of a shuffle, where it needs to be interpreted as 32bits.
|
||||
const bool fmt_16_bits = (psm_s.bpp == 16 && GSLocalMemory::m_psm[dst_match->m_TEX0.PSM].bpp == 16 && !dst->m_32_bits_fmt);
|
||||
if (type == DepthStencil)
|
||||
{
|
||||
GL_CACHE("TC: Lookup Target(Depth) %dx%d, hit Color (0x%x, %s was %s)", new_size.x, new_size.y, bp, psm_str(TEX0.PSM), psm_str(dst_match->m_TEX0.PSM));
|
||||
@@ -608,8 +580,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
|
||||
//
|
||||
// From a performance point of view, it might cost a little on big upscaling
|
||||
// but normally few RT are miss so it must remain reasonable.
|
||||
bool supported_fmt = m_can_convert_depth || psm_s.depth == 0;
|
||||
if (m_preload_frame && TEX0.TBW > 0 && supported_fmt)
|
||||
bool supported_fmt = !GSConfig.UserHacks_DisableDepthSupport || psm_s.depth == 0;
|
||||
if (GSConfig.PreloadFrameWithGSData && TEX0.TBW > 0 && supported_fmt)
|
||||
{
|
||||
GL_INS("Preloading the RT DATA");
|
||||
// RT doesn't have height but if we use a too big value, we will read outside of the GS memory.
|
||||
@@ -644,7 +616,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
|
||||
// must invalidate the Target/Depth respectively
|
||||
void GSTextureCache::InvalidateVideoMemType(int type, u32 bp)
|
||||
{
|
||||
if (!m_can_convert_depth)
|
||||
if (GSConfig.UserHacks_DisableDepthSupport)
|
||||
return;
|
||||
|
||||
auto& list = m_dst[type];
|
||||
@@ -761,7 +733,7 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r
|
||||
|
||||
// No point keeping invalidated sources around when the hash cache is active,
|
||||
// we can just re-hash and create a new source from the cached texture.
|
||||
if (s->m_from_hash_cache || (m_disable_partial_invalidation && s->m_repeating))
|
||||
if (s->m_from_hash_cache || (GSConfig.UserHacks_DisablePartialInvalidation && s->m_repeating))
|
||||
{
|
||||
m_src.RemoveAt(s);
|
||||
}
|
||||
@@ -937,7 +909,7 @@ void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r
|
||||
if (psm == PSM_PSMZ32 || psm == PSM_PSMZ24 || psm == PSM_PSMZ16 || psm == PSM_PSMZ16S)
|
||||
{
|
||||
GL_INS("ERROR: InvalidateLocalMem depth format isn't supported (%d,%d to %d,%d)", r.x, r.y, r.z, r.w);
|
||||
if (m_can_convert_depth)
|
||||
if (!GSConfig.UserHacks_DisableDepthSupport)
|
||||
{
|
||||
auto& dss = m_dst[DepthStencil];
|
||||
for (auto it = dss.rbegin(); it != dss.rend(); ++it) // Iterate targets from LRU to MRU.
|
||||
@@ -986,7 +958,7 @@ void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r
|
||||
if (t->m_32_bits_fmt && t->m_TEX0.PSM > PSM_PSMCT24)
|
||||
t->m_TEX0.PSM = PSM_PSMCT32;
|
||||
|
||||
if (GSTextureCache::m_disable_partial_invalidation)
|
||||
if (GSConfig.UserHacks_DisablePartialInvalidation)
|
||||
{
|
||||
Read(t, r.rintersect(t->m_valid));
|
||||
}
|
||||
@@ -1430,7 +1402,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
float modx = 0.0f;
|
||||
float mody = 0.0f;
|
||||
|
||||
if (UserHacks_HalfPixelOffset && hack)
|
||||
if (GSConfig.UserHacks_HalfPixelOffset == 1 && hack)
|
||||
{
|
||||
switch(m_renderer->GetUpscaleMultiplier())
|
||||
{
|
||||
@@ -1607,7 +1579,7 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(const GIFRegTEX0& TEX0, int
|
||||
{
|
||||
ASSERT(type == RenderTarget || type == DepthStencil);
|
||||
|
||||
Target* t = new Target(m_renderer, TEX0, m_can_convert_depth, type);
|
||||
Target* t = new Target(m_renderer, TEX0, !GSConfig.UserHacks_DisableDepthSupport, type);
|
||||
|
||||
// FIXME: initial data should be unswizzled from local mem in Update() if dirty
|
||||
|
||||
@@ -1886,7 +1858,7 @@ void GSTextureCache::Source::Update(const GSVector4i& rect, int level)
|
||||
int i = (bn.blkY() << 7) + bn.blkX();
|
||||
u32 block = bn.valueNoWrap();
|
||||
|
||||
if (block < MAX_BLOCKS || m_wrap_gs_mem)
|
||||
if (block < MAX_BLOCKS || GSConfig.WrapGSMem)
|
||||
{
|
||||
u32 addr = i % MAX_BLOCKS;
|
||||
|
||||
@@ -1913,7 +1885,7 @@ void GSTextureCache::Source::Update(const GSVector4i& rect, int level)
|
||||
{
|
||||
u32 block = bn.valueNoWrap();
|
||||
|
||||
if (block < MAX_BLOCKS || m_wrap_gs_mem)
|
||||
if (block < MAX_BLOCKS || GSConfig.WrapGSMem)
|
||||
{
|
||||
block %= MAX_BLOCKS;
|
||||
|
||||
|
||||
@@ -282,13 +282,7 @@ protected:
|
||||
std::unordered_map<HashCacheKey, HashCacheEntry, HashCacheKeyHash> m_hash_cache;
|
||||
u64 m_hash_cache_memory_usage = 0;
|
||||
FastList<Target*> m_dst[2];
|
||||
bool m_preload_frame;
|
||||
static u8* m_temp;
|
||||
bool m_can_convert_depth;
|
||||
bool m_cpu_fb_conversion;
|
||||
static bool m_disable_partial_invalidation;
|
||||
bool m_texture_inside_rt;
|
||||
static bool m_wrap_gs_mem;
|
||||
constexpr static size_t S_SURFACE_OFFSET_CACHE_MAX_SIZE = std::numeric_limits<u16>::max();
|
||||
std::unordered_map<SurfaceOffsetKey, SurfaceOffset, SurfaceOffsetKeyHash, SurfaceOffsetKeyEqual> m_surface_offset_cache;
|
||||
|
||||
@@ -326,9 +320,6 @@ public:
|
||||
void InvalidateLocalMem(const GSOffset& off, const GSVector4i& r);
|
||||
|
||||
void IncAge();
|
||||
bool UserHacks_HalfPixelOffset;
|
||||
|
||||
bool ShallSearchTextureInsideRt();
|
||||
|
||||
const char* to_string(int type)
|
||||
{
|
||||
|
||||
@@ -319,7 +319,7 @@ void GSTextureReplacements::ReloadReplacementMap()
|
||||
if (!name.has_value())
|
||||
continue;
|
||||
|
||||
DevCon.WriteLn("Found %ux%u replacement '%*s'", name->Width(), name->Height(), static_cast<int>(filename.size()), filename.data());
|
||||
DevCon.WriteLn("Found %ux%u replacement '%.*s'", name->Width(), name->Height(), static_cast<int>(filename.size()), filename.data());
|
||||
s_replacement_texture_filenames.emplace(std::move(name.value()), std::move(fd.FileName));
|
||||
}
|
||||
|
||||
@@ -564,7 +564,7 @@ void GSTextureReplacements::DumpTexture(const GSTextureCache::HashCacheKey& hash
|
||||
return;
|
||||
|
||||
const std::string_view title(FileSystem::GetFileTitleFromPath(filename));
|
||||
DevCon.WriteLn("Dumping %ux%u texture '%*s'.", name.Width(), name.Height(), static_cast<int>(title.size()), title.data());
|
||||
DevCon.WriteLn("Dumping %ux%u texture '%.*s'.", name.Width(), name.Height(), static_cast<int>(title.size()), title.data());
|
||||
|
||||
// compute width/height
|
||||
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM];
|
||||
|
||||
@@ -881,7 +881,7 @@ GLuint GSDeviceOGL::CreateSampler(PSSamplerSelector sel)
|
||||
|
||||
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
const int anisotropy = theApp.GetConfigI("MaxAnisotropy");
|
||||
const int anisotropy = GSConfig.MaxAnisotropy;
|
||||
if (anisotropy && sel.aniso)
|
||||
{
|
||||
if (GLExtension::Has("GL_ARB_texture_filter_anisotropic"))
|
||||
|
||||
@@ -30,22 +30,8 @@ using namespace Xbyak;
|
||||
// If use_lod, m_local.gd->tex, else m_local.gd->tex[0]
|
||||
#define _64_m_local__gd__tex r14
|
||||
|
||||
#define _rip_local(field) ((is32 || m_rip) ? ptr[rip + (char*)&m_local.field] : ptr[_m_local + OFFSETOF(GSScanlineLocalData, field)])
|
||||
#define _rip_global(field) ((is32 || m_rip) ? ptr[rip + (char*)&m_local.gd->field] : ptr[_m_local__gd + OFFSETOF(GSScanlineGlobalData, field)])
|
||||
|
||||
/// Executes the given code only if targeting 32-bit
|
||||
#define ONLY32(code) if (is32) (code)
|
||||
|
||||
/// Executes the given code only if targeting 64-bit
|
||||
#define ONLY64(code) if (is64) (code)
|
||||
|
||||
/// Combines temporary with either dst64 on 64-bit or src32 on 32-bit
|
||||
/// Follow up with an ONLY32 save back to src32
|
||||
#define REG_64_MEM_32(operation, dst64, temporary, src32) \
|
||||
if (is32) \
|
||||
operation(temporary, src32); \
|
||||
else \
|
||||
operation(dst64, temporary)
|
||||
#define _rip_local(field) ((m_rip) ? ptr[rip + (char*)&m_local.field] : ptr[_m_local + OFFSETOF(GSScanlineLocalData, field)])
|
||||
#define _rip_global(field) ((m_rip) ? ptr[rip + (char*)&m_local.gd->field] : ptr[_m_local__gd + OFFSETOF(GSScanlineGlobalData, field)])
|
||||
|
||||
/// On AVX, does a v-prefixed separate destination operation
|
||||
/// On SSE, moves src1 into dst using movdqa, then does the operation
|
||||
@@ -67,14 +53,7 @@ using namespace Xbyak;
|
||||
#define MOVE_IF_64(operation, dst, src64, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (is64) \
|
||||
{ \
|
||||
THREEARG(operation, dst, src64, __VA_ARGS__); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
operation(dst, __VA_ARGS__); \
|
||||
} \
|
||||
THREEARG(operation, dst, src64, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define USING_XMM DRAW_SCANLINE_USING_XMM
|
||||
@@ -105,21 +84,21 @@ GSDrawScanlineCodeGenerator2::GSDrawScanlineCodeGenerator2(Xbyak::CodeGenerator*
|
||||
, m_local(*(GSScanlineLocalData*)param)
|
||||
, m_rip(false)
|
||||
#ifdef _WIN32
|
||||
, a0(rcx) , a1(rdx)
|
||||
, a2(r8) , a3(is64 ? r9 : rbx)
|
||||
, t0(rdi) , t1(rsi)
|
||||
, t2(is64 ? r8 : rbp), t3(r9)
|
||||
, a0(rcx), a1(rdx)
|
||||
, a2(r8) , a3(r9)
|
||||
, t0(rdi), t1(rsi)
|
||||
, t2(r8) , t3(r9)
|
||||
#else
|
||||
, a0(is64 ? rdi : rcx), a1(is64 ? rsi : rdx)
|
||||
, a2(is64 ? rdx : r8), a3(is64 ? rcx : rbx)
|
||||
, t0(is64 ? r8 : rdi), t1(is64 ? r9 : rsi)
|
||||
, t2(is64 ? rcx : rbp), t3(is64 ? rsi : r8)
|
||||
, a0(rdi), a1(rsi)
|
||||
, a2(rdx), a3(rcx)
|
||||
, t0(r8) , t1(r9)
|
||||
, t2(rcx), t3(rsi)
|
||||
#endif
|
||||
, _g_const(chooseLocal(&*g_const, _64_g_const))
|
||||
, _m_local(chooseLocal(&m_local, _64_m_local))
|
||||
, _m_local__gd(chooseLocal(m_local.gd, _64_m_local__gd))
|
||||
, _m_local__gd__vm(chooseLocal(m_local.gd->vm, _64_m_local__gd__vm))
|
||||
, _rb(xym5), _ga(xym6), _fm(xym3), _zm(xym4), _fd(xym2), _test(is64 ? xym15 : xym7)
|
||||
, _rb(xym5), _ga(xym6), _fm(xym3), _zm(xym4), _fd(xym2), _test(xym15)
|
||||
, _z(xym8), _f(xym9), _s(xym10), _t(xym11), _q(xym12), _f_rb(xym13), _f_ga(xym14)
|
||||
{
|
||||
m_sel.key = key;
|
||||
@@ -132,8 +111,7 @@ GSDrawScanlineCodeGenerator2::GSDrawScanlineCodeGenerator2(Xbyak::CodeGenerator*
|
||||
|
||||
GSDrawScanlineCodeGenerator2::LocalAddr GSDrawScanlineCodeGenerator2::loadAddress(AddressReg reg, const void* addr)
|
||||
{
|
||||
if (is64)
|
||||
mov(reg, (size_t)addr);
|
||||
mov(reg, (size_t)addr);
|
||||
return choose3264((size_t)addr, reg);
|
||||
}
|
||||
|
||||
@@ -352,51 +330,41 @@ void GSDrawScanlineCodeGenerator2::Generate()
|
||||
m_rip &= (size_t)&m_local < 0x80000000;
|
||||
m_rip &= (size_t)&m_local.gd < 0x80000000;
|
||||
|
||||
if (is32)
|
||||
{
|
||||
push(rbx);
|
||||
push(rsi);
|
||||
push(rdi);
|
||||
push(rbp);
|
||||
}
|
||||
else
|
||||
{
|
||||
push(rbp);
|
||||
mov(rbp, rsp); // Stack traces look much nicer this way
|
||||
push(rbp);
|
||||
mov(rbp, rsp); // Stack traces look much nicer this way
|
||||
#ifdef _WIN32
|
||||
push(rbx);
|
||||
push(rsi);
|
||||
push(rdi);
|
||||
push(r12);
|
||||
push(r13);
|
||||
push(r14);
|
||||
push(rbx);
|
||||
push(rsi);
|
||||
push(rdi);
|
||||
push(r12);
|
||||
push(r13);
|
||||
push(r14);
|
||||
|
||||
sub(rsp, _64_win_stack_size);
|
||||
sub(rsp, _64_win_stack_size);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
movdqa(ptr[rsp + _64_win_xmm_start + 16 * i], Xmm(i + 6));
|
||||
}
|
||||
#else
|
||||
mov(ptr[rsp + _64_rz_rbx], rbx);
|
||||
if (!m_rip)
|
||||
{
|
||||
mov(ptr[rsp + _64_rz_r12], r12);
|
||||
mov(ptr[rsp + _64_rz_r13], r13);
|
||||
}
|
||||
mov(ptr[rsp + _64_rz_r14], r14);
|
||||
mov(ptr[rsp + _64_rz_r15], r15);
|
||||
#endif
|
||||
mov(_64_g_const, (size_t)&*g_const);
|
||||
if (!m_rip)
|
||||
{
|
||||
mov(_64_m_local, (size_t)&m_local);
|
||||
mov(_64_m_local__gd, _rip_local(gd));
|
||||
}
|
||||
|
||||
if (need_clut)
|
||||
mov(_64_m_local__gd__clut, _rip_global(clut));
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
movdqa(ptr[rsp + _64_win_xmm_start + 16 * i], Xmm(i + 6));
|
||||
}
|
||||
#else
|
||||
mov(ptr[rsp + _64_rz_rbx], rbx);
|
||||
if (!m_rip)
|
||||
{
|
||||
mov(ptr[rsp + _64_rz_r12], r12);
|
||||
mov(ptr[rsp + _64_rz_r13], r13);
|
||||
}
|
||||
mov(ptr[rsp + _64_rz_r14], r14);
|
||||
mov(ptr[rsp + _64_rz_r15], r15);
|
||||
#endif
|
||||
mov(_64_g_const, (size_t)&*g_const);
|
||||
if (!m_rip)
|
||||
{
|
||||
mov(_64_m_local, (size_t)&m_local);
|
||||
mov(_64_m_local__gd, _rip_local(gd));
|
||||
}
|
||||
|
||||
if (need_clut)
|
||||
mov(_64_m_local__gd__clut, _rip_global(clut));
|
||||
|
||||
Init();
|
||||
|
||||
@@ -615,47 +583,33 @@ L("step");
|
||||
|
||||
L("exit");
|
||||
|
||||
|
||||
|
||||
if (is32)
|
||||
{
|
||||
pop(ebp);
|
||||
pop(edi);
|
||||
pop(esi);
|
||||
pop(ebx);
|
||||
|
||||
ret(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _WIN32
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
movdqa(Xmm(i + 6), ptr[rsp + _64_win_xmm_start + 16 * i]);
|
||||
}
|
||||
add(rsp, _64_win_stack_size);
|
||||
|
||||
pop(r14);
|
||||
pop(r13);
|
||||
pop(r12);
|
||||
pop(rdi);
|
||||
pop(rsi);
|
||||
pop(rbx);
|
||||
#else
|
||||
mov(rbx, ptr[rsp + _64_rz_rbx]);
|
||||
if (!m_rip)
|
||||
{
|
||||
mov(r12, ptr[rsp + _64_rz_r12]);
|
||||
mov(r13, ptr[rsp + _64_rz_r13]);
|
||||
}
|
||||
mov(r14, ptr[rsp + _64_rz_r14]);
|
||||
mov(r15, ptr[rsp + _64_rz_r15]);
|
||||
#endif
|
||||
pop(rbp);
|
||||
if (isYmm)
|
||||
vzeroupper();
|
||||
ret();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
movdqa(Xmm(i + 6), ptr[rsp + _64_win_xmm_start + 16 * i]);
|
||||
}
|
||||
add(rsp, _64_win_stack_size);
|
||||
|
||||
pop(r14);
|
||||
pop(r13);
|
||||
pop(r12);
|
||||
pop(rdi);
|
||||
pop(rsi);
|
||||
pop(rbx);
|
||||
#else
|
||||
mov(rbx, ptr[rsp + _64_rz_rbx]);
|
||||
if (!m_rip)
|
||||
{
|
||||
mov(r12, ptr[rsp + _64_rz_r12]);
|
||||
mov(r13, ptr[rsp + _64_rz_r13]);
|
||||
}
|
||||
mov(r14, ptr[rsp + _64_rz_r14]);
|
||||
mov(r15, ptr[rsp + _64_rz_r15]);
|
||||
#endif
|
||||
pop(rbp);
|
||||
if (isYmm)
|
||||
vzeroupper();
|
||||
ret();
|
||||
}
|
||||
|
||||
/// Inputs: a0=pixels, a1=left, a2[x64]=top, a3[x64]=v
|
||||
@@ -683,7 +637,7 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
and(eax, a0.cvt32());
|
||||
if (isXmm)
|
||||
shl(eax, 4); // * sizeof(m_test[0])
|
||||
ONLY64(cdqe());
|
||||
cdqe();
|
||||
|
||||
if (isXmm)
|
||||
{
|
||||
@@ -713,43 +667,19 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
// rbx = left
|
||||
// Free: rax, t0, t1
|
||||
|
||||
if (is64)
|
||||
{
|
||||
// GSVector2i* fza_base = &m_local.gd->fzbr[top];
|
||||
mov(rax, _rip_global(fzbr));
|
||||
lea(t1, ptr[rax + a2 * 8]);
|
||||
// GSVector2i* fza_base = &m_local.gd->fzbr[top];
|
||||
mov(rax, _rip_global(fzbr));
|
||||
lea(t1, ptr[rax + a2 * 8]);
|
||||
|
||||
// GSVector2i* fza_offset = &m_local.gd->fzbc[left >> 2];
|
||||
mov(rax, _rip_global(fzbc));
|
||||
lea(t0, ptr[rax + rbx * 2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector2i* fza_base = &m_local.gd->fzbr[top];
|
||||
mov(t1, ptr[rsp + _top]);
|
||||
lea(t1, ptr[t1 * 8]);
|
||||
add(t1, ptr[&m_local.gd->fzbr]);
|
||||
|
||||
// GSVector2i* fza_offset = &m_local.gd->fzbc[left >> 2];
|
||||
lea(t0, ptr[rbx * 2]);
|
||||
add(t0, ptr[(size_t)&m_local.gd->fzbc]);
|
||||
}
|
||||
// GSVector2i* fza_offset = &m_local.gd->fzbc[left >> 2];
|
||||
mov(rax, _rip_global(fzbc));
|
||||
lea(t0, ptr[rax + rbx * 2]);
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS && (m_sel.fwrite && m_sel.fge || m_sel.zb) || m_sel.fb && (m_sel.edge || m_sel.tfx != TFX_NONE || m_sel.iip))
|
||||
{
|
||||
// a1 = &m_local.d[skip] // note a1 was (skip << 4)
|
||||
|
||||
if (is64)
|
||||
{
|
||||
lea(rax, _rip_local(d));
|
||||
lea(a1, ptr[rax + a1 * 8]);
|
||||
}
|
||||
else
|
||||
{
|
||||
lea(a1, ptr[(size_t)m_local.d + a1 * 8]);
|
||||
// a3 starts on the stack in x86, we want it in a register
|
||||
mov(a3, ptr[rsp + _v]);
|
||||
}
|
||||
lea(rax, _rip_local(d));
|
||||
lea(a1, ptr[rax + a1 * 8]);
|
||||
}
|
||||
|
||||
// a0 = steps (rcx | rdi)
|
||||
@@ -760,8 +690,8 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
// t1 = fza_base (rsi | r9 )
|
||||
// Free: rax
|
||||
|
||||
const XYm& f = is64 ? _f : xym1;
|
||||
const XYm& z = is64 ? _z : xym0;
|
||||
const XYm& f = _f;
|
||||
const XYm& z = _z;
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
@@ -777,9 +707,6 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
pshufhw(f, f, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
pshufd(f, f, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
paddw(f, ptr[a1 + offsetof(GSScanlineLocalData::skip, f)]);
|
||||
|
||||
if (is32) // _f is shared on x86
|
||||
movdqa(ptr[&m_local.temp.f], f);
|
||||
}
|
||||
|
||||
if (m_sel.zb)
|
||||
@@ -788,17 +715,7 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
{
|
||||
// z = vp.zzzz() + m_local.d[skip].z;
|
||||
shufps(z, z, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
if (is64)
|
||||
{
|
||||
addps(z, ptr[a1 + offsetof(GSScanlineLocalData::skip, z)]);
|
||||
}
|
||||
else
|
||||
{
|
||||
movaps(ptr[&m_local.temp.z], z);
|
||||
movaps(xym2, ptr[a1 + offsetof(GSScanlineLocalData::skip, z)]);
|
||||
movaps(ptr[&m_local.temp.zo], xym2);
|
||||
addps(z, xym2);
|
||||
}
|
||||
addps(z, ptr[a1 + offsetof(GSScanlineLocalData::skip, z)]);
|
||||
}
|
||||
else
|
||||
pbroadcastdLocal(z, _rip_local(p.z));
|
||||
@@ -812,7 +729,7 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
pbroadcastdLocal(z, _rip_local(p.z));
|
||||
}
|
||||
|
||||
if (m_sel.fwrite && m_sel.fge && is64)
|
||||
if (m_sel.fwrite && m_sel.fge)
|
||||
pbroadcastwLocal(_f, _rip_local(p.f));
|
||||
}
|
||||
|
||||
@@ -840,8 +757,8 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
{
|
||||
// a1 = &m_local.d[skip]
|
||||
|
||||
const XYm& s = is64 ? _s : xym2;
|
||||
const XYm& t = is64 ? _t : xym3;
|
||||
const XYm& s = _s;
|
||||
const XYm& t = _t;
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
@@ -863,19 +780,16 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
}
|
||||
else if (m_sel.ltf)
|
||||
{
|
||||
XYm vf = is64 ? xym7 : xym6;
|
||||
XYm vf = xym7;
|
||||
pshuflw(vf, t, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(vf, vf, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
psrlw(vf, 12);
|
||||
movdqa(_rip_local(temp.vf), vf);
|
||||
}
|
||||
|
||||
ONLY32(movdqa(_rip_local(temp.s), s));
|
||||
ONLY32(movdqa(_rip_local(temp.t), t));
|
||||
}
|
||||
else
|
||||
{
|
||||
const XYm& q = is64 ? _q : vt;
|
||||
const XYm& q = _q;
|
||||
|
||||
// s = vt.xxxx() + m_local.d[skip].s;
|
||||
// t = vt.yyyy() + m_local.d[skip].t;
|
||||
@@ -891,7 +805,7 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
{
|
||||
movaps(s, vt);
|
||||
movaps(t, vt);
|
||||
ONLY64(movaps(q, vt));
|
||||
movaps(q, vt);
|
||||
|
||||
shufps(s, s, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
shufps(t, t, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
@@ -901,20 +815,13 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
addps(s, ptr[a1 + offsetof(GSScanlineLocalData::skip, s)]);
|
||||
addps(t, ptr[a1 + offsetof(GSScanlineLocalData::skip, t)]);
|
||||
addps(q, ptr[a1 + offsetof(GSScanlineLocalData::skip, q)]);
|
||||
|
||||
if (is32)
|
||||
{
|
||||
movaps(ptr[&m_local.temp.s], s);
|
||||
movaps(ptr[&m_local.temp.t], t);
|
||||
movaps(ptr[&m_local.temp.q], q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(m_sel.tfx == TFX_DECAL && m_sel.tcc))
|
||||
{
|
||||
const XYm& f_rb = is64 ? _f_rb : xym5;
|
||||
const XYm& f_ga = is64 ? _f_ga : xym6;
|
||||
const XYm& f_rb = _f_rb;
|
||||
const XYm& f_ga = _f_ga;
|
||||
if (m_sel.iip)
|
||||
{
|
||||
// GSVector4i vc = GSVector4i(v.c);
|
||||
@@ -942,38 +849,32 @@ void GSDrawScanlineCodeGenerator2::Init()
|
||||
|
||||
paddw(f_rb, ptr[a1 + offsetof(GSScanlineLocalData::skip, rb)]);
|
||||
paddw(f_ga, ptr[a1 + offsetof(GSScanlineLocalData::skip, ga)]);
|
||||
|
||||
ONLY32(movdqa(ptr[&m_local.temp.rb], f_rb));
|
||||
ONLY32(movdqa(ptr[&m_local.temp.ga], f_ga));
|
||||
}
|
||||
else if (is64 || m_sel.tfx == TFX_NONE)
|
||||
else
|
||||
{
|
||||
movdqa(f_rb, _rip_local(c.rb));
|
||||
movdqa(f_ga, _rip_local(c.ga));
|
||||
}
|
||||
|
||||
ONLY64(movdqa(_rb, _f_rb));
|
||||
ONLY64(movdqa(_ga, _f_ga));
|
||||
movdqa(_rb, _f_rb);
|
||||
movdqa(_ga, _f_ga);
|
||||
}
|
||||
}
|
||||
|
||||
if (is64)
|
||||
if (m_sel.fwrite && m_sel.fpsm == 2 && m_sel.dthe)
|
||||
{
|
||||
if (m_sel.fwrite && m_sel.fpsm == 2 && m_sel.dthe)
|
||||
{
|
||||
// On linux, a2 is edx which will be used for fzm
|
||||
// In all case, it will require a mov in dthe code, so let's keep the value on the stack
|
||||
mov(ptr[rsp + _top], a2);
|
||||
}
|
||||
// On linux, a2 is edx which will be used for fzm
|
||||
// In all case, it will require a mov in dthe code, so let's keep the value on the stack
|
||||
mov(ptr[rsp + _top], a2);
|
||||
}
|
||||
|
||||
mov(_64_m_local__gd__vm, _rip_global(vm));
|
||||
if (m_sel.fb && m_sel.tfx != TFX_NONE)
|
||||
{
|
||||
if (use_lod)
|
||||
lea(_64_m_local__gd__tex, _rip_global(tex));
|
||||
else
|
||||
mov(_64_m_local__gd__tex, _rip_global(tex));
|
||||
}
|
||||
mov(_64_m_local__gd__vm, _rip_global(vm));
|
||||
if (m_sel.fb && m_sel.tfx != TFX_NONE)
|
||||
{
|
||||
if (use_lod)
|
||||
lea(_64_m_local__gd__tex, _rip_global(tex));
|
||||
else
|
||||
mov(_64_m_local__gd__tex, _rip_global(tex));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -991,8 +892,8 @@ void GSDrawScanlineCodeGenerator2::Step()
|
||||
|
||||
add(t0, vecsize / 2);
|
||||
|
||||
const XYm& z = is64 ? _z : xym0;
|
||||
const XYm& f = is64 ? _f : xym1;
|
||||
const XYm& z =_z;
|
||||
const XYm& f =_f;
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
@@ -1004,13 +905,6 @@ void GSDrawScanlineCodeGenerator2::Step()
|
||||
{
|
||||
pbroadcastdLocal(z, _rip_local(p.z));
|
||||
}
|
||||
else if (is32)
|
||||
{
|
||||
broadcastssLocal(z, _rip_local_d_p(z));
|
||||
addps(z, _rip_local(temp.zo));
|
||||
movaps(_rip_local(temp.zo), z);
|
||||
addps(z, _rip_local(temp.z));
|
||||
}
|
||||
else
|
||||
{
|
||||
BROADCAST_AND_OP(vbroadcastss, addps, z, xym0, _rip_local_d_p(z));
|
||||
@@ -1021,23 +915,7 @@ void GSDrawScanlineCodeGenerator2::Step()
|
||||
|
||||
if (m_sel.fwrite && m_sel.fge)
|
||||
{
|
||||
if (is32)
|
||||
{
|
||||
pbroadcastwLocal(f, _rip_local_d_p(f));
|
||||
paddw(f, _rip_local(temp.f));
|
||||
movdqa(_rip_local(temp.f), f);
|
||||
}
|
||||
else
|
||||
{
|
||||
BROADCAST_AND_OP(vpbroadcastw, paddw, f, xym0, _rip_local_d_p(f));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is32 && m_sel.ztest)
|
||||
{
|
||||
pbroadcastdLocal(z, _rip_local(p.z));
|
||||
BROADCAST_AND_OP(vpbroadcastw, paddw, f, xym0, _rip_local_d_p(f));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1047,7 +925,7 @@ void GSDrawScanlineCodeGenerator2::Step()
|
||||
{
|
||||
if (m_sel.fst)
|
||||
{
|
||||
const XYm& stq = is64 ? xym0 : xym4;
|
||||
const XYm& stq = xym0;
|
||||
// GSVector4i stq = m_local.d4.stq;
|
||||
|
||||
// s += stq.xxxx();
|
||||
@@ -1055,28 +933,22 @@ void GSDrawScanlineCodeGenerator2::Step()
|
||||
|
||||
broadcasti128(stq, _rip_local_d(stq));
|
||||
|
||||
XYm s = is64 ? xym1 : xym2;
|
||||
XYm s = xym1;
|
||||
pshufd(s, stq, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
REG_64_MEM_32(paddd, _s, s, _rip_local(temp.s));
|
||||
ONLY32(movdqa(_rip_local(temp.s), s));
|
||||
paddd(_s, s);
|
||||
|
||||
XYm t = is64 ? xym1 : xym3;
|
||||
XYm t = xym1;
|
||||
if (m_sel.prim != GS_SPRITE_CLASS || m_sel.mmin)
|
||||
{
|
||||
pshufd(t, stq, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
REG_64_MEM_32(paddd, _t, t, _rip_local(temp.t));
|
||||
ONLY32(movdqa(_rip_local(temp.t), t));
|
||||
}
|
||||
else
|
||||
{
|
||||
ONLY32(movdqa(t, _rip_local(temp.t)));
|
||||
paddd(_t, t);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const XYm& s = xym2;
|
||||
const XYm& t = xym3;
|
||||
const XYm& q = is64 ? xym1 : xym4;
|
||||
const XYm& q = xym1;
|
||||
// GSVector4 stq = m_local.d4.stq;
|
||||
|
||||
// s += stq.xxxx();
|
||||
@@ -1102,13 +974,9 @@ void GSDrawScanlineCodeGenerator2::Step()
|
||||
shufps(q, q, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
}
|
||||
|
||||
REG_64_MEM_32(addps, _s, s, _rip_local(temp.s));
|
||||
REG_64_MEM_32(addps, _t, t, _rip_local(temp.t));
|
||||
REG_64_MEM_32(addps, _q, q, _rip_local(temp.q));
|
||||
|
||||
ONLY32(movaps(_rip_local(temp.s), s));
|
||||
ONLY32(movaps(_rip_local(temp.t), t));
|
||||
ONLY32(movaps(_rip_local(temp.q), q));
|
||||
addps(_s, s);
|
||||
addps(_t, t);
|
||||
addps(_q, q);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1116,7 +984,7 @@ void GSDrawScanlineCodeGenerator2::Step()
|
||||
{
|
||||
if (m_sel.iip)
|
||||
{
|
||||
XYm c = is64 ? xym0 : xym7;
|
||||
XYm c = xym0;
|
||||
// GSVector4i c = m_local.d4.c;
|
||||
|
||||
// rb = rb.add16(c.xxxx());
|
||||
@@ -1127,29 +995,18 @@ void GSDrawScanlineCodeGenerator2::Step()
|
||||
pshufd(_rb, c, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
pshufd(_ga, c, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
|
||||
REG_64_MEM_32(paddw, _f_rb, _rb, _rip_local(temp.rb));
|
||||
REG_64_MEM_32(paddw, _f_ga, _ga, _rip_local(temp.ga));
|
||||
paddw(_f_rb, _rb);
|
||||
paddw(_f_ga, _ga);
|
||||
|
||||
// FIXME: color may underflow and roll over at the end of the line, if decreasing
|
||||
|
||||
pxor(c, c);
|
||||
pmaxsw(is64 ? _f_rb : _rb, c);
|
||||
pmaxsw(is64 ? _f_ga : _ga, c);
|
||||
|
||||
ONLY32(movdqa(_rip_local(temp.rb), _rb));
|
||||
ONLY32(movdqa(_rip_local(temp.ga), _ga));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_sel.tfx == TFX_NONE)
|
||||
{
|
||||
ONLY32(movdqa(_rb, ptr[&m_local.c.rb]));
|
||||
ONLY32(movdqa(_ga, ptr[&m_local.c.ga]));
|
||||
}
|
||||
pmaxsw(_f_rb, c);
|
||||
pmaxsw(_f_ga, c);
|
||||
}
|
||||
|
||||
ONLY64(movdqa(_rb, _f_rb));
|
||||
ONLY64(movdqa(_ga, _f_ga));
|
||||
movdqa(_rb, _f_rb);
|
||||
movdqa(_ga, _f_ga);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1162,7 +1019,7 @@ void GSDrawScanlineCodeGenerator2::Step()
|
||||
and(eax, a0.cvt32());
|
||||
if (isXmm)
|
||||
shl(eax, 4);
|
||||
ONLY64(cdqe());
|
||||
cdqe();
|
||||
|
||||
#if USING_XMM
|
||||
movdqa(_test, ptr[rax + _g_const + offsetof(GSScanlineConstantData, m_test_128b[7])]);
|
||||
@@ -1182,7 +1039,7 @@ void GSDrawScanlineCodeGenerator2::TestZ(const XYm& temp1, const XYm& temp2)
|
||||
return;
|
||||
}
|
||||
|
||||
const XYm& z = is64 ? _z : xym0;
|
||||
const XYm& z = _z;
|
||||
|
||||
// int za = fza_base.y + fza_offset->y;
|
||||
|
||||
@@ -1196,7 +1053,7 @@ void GSDrawScanlineCodeGenerator2::TestZ(const XYm& temp1, const XYm& temp2)
|
||||
{
|
||||
if (m_sel.zequal)
|
||||
{
|
||||
ONLY64(movdqa(xym0, _z));
|
||||
movdqa(xym0, _z);
|
||||
}
|
||||
else if (m_sel.zoverflow)
|
||||
{
|
||||
@@ -1247,7 +1104,7 @@ void GSDrawScanlineCodeGenerator2::TestZ(const XYm& temp1, const XYm& temp2)
|
||||
}
|
||||
else
|
||||
{
|
||||
ONLY64(movdqa(xym0, _z));
|
||||
movdqa(xym0, _z);
|
||||
}
|
||||
|
||||
if (m_sel.ztest)
|
||||
@@ -1312,22 +1169,11 @@ void GSDrawScanlineCodeGenerator2::SampleTexture()
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (is32)
|
||||
{
|
||||
mov(ebx, ptr[&m_local.gd->tex[0]]);
|
||||
|
||||
if (m_sel.tlu)
|
||||
{
|
||||
mov(edx, ptr[&m_local.gd->clut]);
|
||||
}
|
||||
}
|
||||
|
||||
const bool needsMoreRegs = isYmm;
|
||||
|
||||
if (!m_sel.fst)
|
||||
{
|
||||
rcpps(xym0, is64 ? _q : xym4);
|
||||
rcpps(xym0, _q);
|
||||
|
||||
MOVE_IF_64(mulps, xym2, _s, xym0);
|
||||
MOVE_IF_64(mulps, xym3, _t, xym0);
|
||||
@@ -1349,21 +1195,19 @@ void GSDrawScanlineCodeGenerator2::SampleTexture()
|
||||
}
|
||||
else
|
||||
{
|
||||
ONLY64(movdqa(xym2, _s));
|
||||
ONLY64(movdqa(xym3, _t));
|
||||
movdqa(xym2, _s);
|
||||
movdqa(xym3, _t);
|
||||
}
|
||||
|
||||
if (m_sel.ltf)
|
||||
{
|
||||
const XYm& vf = is64 ? xym7 : xym0;
|
||||
const XYm& vf = xym7;
|
||||
|
||||
// GSVector4i uf = u.xxzzlh().srl16(12);
|
||||
|
||||
pshuflw(xym4, xym2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(xym4, xym4, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
psrlw(xym4, 12);
|
||||
if (is32 && needsMoreRegs)
|
||||
movdqa(_rip_local(temp.uf), xym4);
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
@@ -1372,10 +1216,10 @@ void GSDrawScanlineCodeGenerator2::SampleTexture()
|
||||
pshuflw(vf, xym3, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(vf, vf, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
psrlw(vf, 12);
|
||||
if (is32 || needsMoreRegs)
|
||||
if (needsMoreRegs)
|
||||
movdqa(_rip_local(temp.vf), vf);
|
||||
}
|
||||
else if (is64 && !needsMoreRegs)
|
||||
else if (!needsMoreRegs)
|
||||
{
|
||||
movdqa(vf, _rip_local(temp.vf));
|
||||
}
|
||||
@@ -1484,8 +1328,8 @@ void GSDrawScanlineCodeGenerator2::SampleTexture_TexelReadHelper(int mip_offset)
|
||||
// c10 = addr10.gather32_32((const u32/u8*)tex[, clut]);
|
||||
// c11 = addr11.gather32_32((const u32/u8*)tex[, clut]);
|
||||
|
||||
const XYm& tmp1 = is64 ? xym7 : xym4; // OK to destroy if needsMoreRegs
|
||||
const XYm& tmp2 = is64 ? xym4 : xym7;
|
||||
const XYm& tmp1 = xym7; // OK to destroy if needsMoreRegs
|
||||
const XYm& tmp2 = xym4;
|
||||
// d0 d1 d2s0 d3s1 s2 s3
|
||||
ReadTexel4(xym5, xym6, xym0, xym2, xym1, xym3, tmp1, tmp2, mip_offset);
|
||||
|
||||
@@ -1496,9 +1340,6 @@ void GSDrawScanlineCodeGenerator2::SampleTexture_TexelReadHelper(int mip_offset)
|
||||
// xym6 = c00
|
||||
// xym7 = used[x86] vf[x64&&!needsMoreRegs]
|
||||
|
||||
if (is32 && needsMoreRegs)
|
||||
movdqa(xym4, _rip_local(temp.uf));
|
||||
|
||||
// GSVector4i rb00 = c00 & mask;
|
||||
// GSVector4i ga00 = (c00 >> 8) & mask;
|
||||
|
||||
@@ -1565,8 +1406,8 @@ void GSDrawScanlineCodeGenerator2::SampleTexture_TexelReadHelper(int mip_offset)
|
||||
// rb00 = rb00.lerp16_4(rb10, vf);
|
||||
// ga00 = ga00.lerp16_4(ga10, vf);
|
||||
|
||||
XYm vf = is64 ? xym7 : xym2;
|
||||
if (needsMoreRegs || is32)
|
||||
XYm vf = xym7;
|
||||
if (needsMoreRegs)
|
||||
movdqa(vf, _rip_local(temp.vf));
|
||||
|
||||
lerp16_4(xym5, xym0, vf);
|
||||
@@ -1729,22 +1570,9 @@ void GSDrawScanlineCodeGenerator2::SampleTextureLOD()
|
||||
return;
|
||||
}
|
||||
|
||||
if (is32)
|
||||
{
|
||||
push(t2);
|
||||
|
||||
mov(t2, (size_t)m_local.gd->tex);
|
||||
|
||||
if (m_sel.tlu)
|
||||
{
|
||||
mov(edx, ptr[&m_local.gd->clut]);
|
||||
}
|
||||
}
|
||||
|
||||
const bool needsMoreRegs = isYmm;
|
||||
|
||||
if (is64)
|
||||
movdqa(xym4, _q);
|
||||
movdqa(xym4, _q);
|
||||
|
||||
if (!m_sel.fst)
|
||||
{
|
||||
@@ -1756,6 +1584,11 @@ void GSDrawScanlineCodeGenerator2::SampleTextureLOD()
|
||||
cvttps2dq(xym2, xym2);
|
||||
cvttps2dq(xym3, xym3);
|
||||
}
|
||||
else
|
||||
{
|
||||
movdqa(xym2, _s);
|
||||
movdqa(xym3, _t);
|
||||
}
|
||||
|
||||
// xym2 = u
|
||||
// xym3 = v
|
||||
@@ -1969,7 +1802,7 @@ void GSDrawScanlineCodeGenerator2::SampleTextureLOD()
|
||||
|
||||
if (m_sel.ltf)
|
||||
{
|
||||
const XYm& vf = is64 ? xym7 : xym0;
|
||||
const XYm& vf = xym7;
|
||||
// u -= 0x8000;
|
||||
// v -= 0x8000;
|
||||
|
||||
@@ -1984,15 +1817,13 @@ void GSDrawScanlineCodeGenerator2::SampleTextureLOD()
|
||||
pshuflw(xym4, xym2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(xym4, xym4, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
psrlw(xym4, 12);
|
||||
if (is32 && needsMoreRegs)
|
||||
movdqa(_rip_local(temp.uf), xym4);
|
||||
|
||||
// GSVector4i vf = v.xxzzlh().srl16(1);
|
||||
|
||||
pshuflw(vf, xym3, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(vf, vf, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
psrlw(vf, 12);
|
||||
if (is32 || needsMoreRegs)
|
||||
if (needsMoreRegs)
|
||||
movdqa(_rip_local(temp.vf), vf);
|
||||
}
|
||||
|
||||
@@ -2053,7 +1884,7 @@ void GSDrawScanlineCodeGenerator2::SampleTextureLOD()
|
||||
|
||||
if (m_sel.ltf)
|
||||
{
|
||||
const XYm& vf = is64 ? xym7 : xym0;
|
||||
const XYm& vf = xym7;
|
||||
// u -= 0x8000;
|
||||
// v -= 0x8000;
|
||||
|
||||
@@ -2068,15 +1899,13 @@ void GSDrawScanlineCodeGenerator2::SampleTextureLOD()
|
||||
pshuflw(xym4, xym2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(xym4, xym4, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
psrlw(xym4, 12);
|
||||
if (is32 && needsMoreRegs)
|
||||
movdqa(_rip_local(temp.uf), xym4);
|
||||
|
||||
// GSVector4i vf = v.xxzzlh().srl16(1);
|
||||
|
||||
pshuflw(vf, xym3, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(vf, vf, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
psrlw(vf, 12);
|
||||
if (is32 || needsMoreRegs)
|
||||
if (needsMoreRegs)
|
||||
movdqa(_rip_local(temp.vf), vf);
|
||||
}
|
||||
|
||||
@@ -2126,9 +1955,6 @@ void GSDrawScanlineCodeGenerator2::SampleTextureLOD()
|
||||
lerp16(xym5, xym2, xym0, 0);
|
||||
lerp16(xym6, xym3, xym0, 0);
|
||||
}
|
||||
|
||||
if (is32)
|
||||
pop(t2);
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator2::WrapLOD(const XYm& uv)
|
||||
@@ -2259,9 +2085,9 @@ void GSDrawScanlineCodeGenerator2::AlphaTFX()
|
||||
return;
|
||||
}
|
||||
|
||||
const XYm& f_ga = is64 ? _f_ga : xym4;
|
||||
const XYm& tmpga = is64 ? xym1 : f_ga;
|
||||
const XYm& tmp = is64 ? xym0 : xym3;
|
||||
const XYm& f_ga = _f_ga;
|
||||
const XYm& tmpga = xym1;
|
||||
const XYm& tmp = xym0;
|
||||
Address _32_gaptr = m_sel.iip ? _rip_local(temp.ga) : _rip_local(c.ga);
|
||||
|
||||
switch (m_sel.tfx)
|
||||
@@ -2269,9 +2095,6 @@ void GSDrawScanlineCodeGenerator2::AlphaTFX()
|
||||
case TFX_MODULATE:
|
||||
|
||||
// GSVector4i ga = iip ? gaf : m_local.c.ga;
|
||||
|
||||
ONLY32(movdqa(f_ga, _32_gaptr));
|
||||
|
||||
// gat = gat.modulate16<1>(ga).clamp8();
|
||||
|
||||
modulate16(_ga, f_ga, 1);
|
||||
@@ -2296,8 +2119,6 @@ void GSDrawScanlineCodeGenerator2::AlphaTFX()
|
||||
{
|
||||
// GSVector4i ga = iip ? gaf : m_local.c.ga;
|
||||
|
||||
ONLY32(movdqa(f_ga, _32_gaptr));
|
||||
|
||||
MOVE_IF_64(psrlw, tmpga, f_ga, 7);
|
||||
|
||||
mix16(_ga, tmpga, tmp);
|
||||
@@ -2308,10 +2129,6 @@ void GSDrawScanlineCodeGenerator2::AlphaTFX()
|
||||
case TFX_HIGHLIGHT:
|
||||
|
||||
// GSVector4i ga = iip ? gaf : m_local.c.ga;
|
||||
|
||||
ONLY32(movdqa(f_ga, _32_gaptr));
|
||||
ONLY32(movdqa(xym2, f_ga)); // WHY
|
||||
|
||||
// gat = gat.mix16(!tcc ? ga.srl16(7) : gat.addus8(ga.srl16(7)));
|
||||
|
||||
MOVE_IF_64(psrlw, tmpga, f_ga, 7);
|
||||
@@ -2333,9 +2150,6 @@ void GSDrawScanlineCodeGenerator2::AlphaTFX()
|
||||
{
|
||||
// GSVector4i ga = iip ? gaf : m_local.c.ga;
|
||||
|
||||
ONLY32(movdqa(f_ga, _32_gaptr));
|
||||
ONLY32(movdqa(xym2, f_ga));
|
||||
|
||||
MOVE_IF_64(psrlw, tmpga, f_ga, 7);
|
||||
|
||||
mix16(_ga, tmpga, tmp);
|
||||
@@ -2500,16 +2314,13 @@ void GSDrawScanlineCodeGenerator2::ColorTFX()
|
||||
return;
|
||||
}
|
||||
|
||||
const XYm& f_ga = is64 ? _f_ga : xym2;
|
||||
const XYm& tmpga = is64 ? xym2 : f_ga;
|
||||
const XYm& f_ga = _f_ga;
|
||||
const XYm& tmpga = xym2;
|
||||
|
||||
auto modulate16_1_rb = [&]
|
||||
{
|
||||
// GSVector4i rb = iip ? rbf : m_local.c.rb;
|
||||
if (is64)
|
||||
modulate16(_rb, _f_rb, 1);
|
||||
else
|
||||
modulate16(_rb, m_sel.iip ? _rip_local(temp.rb) : _rip_local(c.rb), 1);
|
||||
modulate16(_rb, _f_rb, 1);
|
||||
};
|
||||
|
||||
switch (m_sel.tfx)
|
||||
@@ -2532,14 +2343,6 @@ void GSDrawScanlineCodeGenerator2::ColorTFX()
|
||||
|
||||
case TFX_HIGHLIGHT:
|
||||
case TFX_HIGHLIGHT2:
|
||||
|
||||
if (m_sel.tfx == TFX_HIGHLIGHT2 && m_sel.tcc)
|
||||
{
|
||||
// GSVector4i ga = iip ? gaf : m_local.c.ga;
|
||||
|
||||
ONLY32(movdqa(f_ga, m_sel.iip ? _rip_local(temp.ga) : _rip_local(c.ga)));
|
||||
}
|
||||
|
||||
// gat = gat.modulate16<1>(ga).add16(af).clamp8().mix16(gat);
|
||||
|
||||
movdqa(xym1, _ga);
|
||||
@@ -2588,21 +2391,12 @@ void GSDrawScanlineCodeGenerator2::Fog()
|
||||
return;
|
||||
}
|
||||
|
||||
const XYm& f = is64 ? _f : xym0;
|
||||
const XYm& tmp = is64 ? xym0 : xym2;
|
||||
const XYm& f = _f;
|
||||
const XYm& tmp = xym0;
|
||||
|
||||
// rb = m_local.gd->frb.lerp16<0>(rb, f);
|
||||
// ga = m_local.gd->fga.lerp16<0>(ga, f).mix16(ga);
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
ONLY32(movdqa(f, _rip_local(temp.f)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ONLY32(pbroadcastwLocal(f, _rip_local(p.f)));
|
||||
}
|
||||
|
||||
movdqa(xym1, _ga);
|
||||
|
||||
pbroadcastdLocal(tmp, _rip_global(frb));
|
||||
@@ -3055,7 +2849,7 @@ void GSDrawScanlineCodeGenerator2::WriteFrame()
|
||||
}
|
||||
|
||||
|
||||
const XYm& tmp = is64 ? xym15 : xym7;
|
||||
const XYm& tmp = xym15;
|
||||
|
||||
if (m_sel.fpsm == 2 && m_sel.dthe)
|
||||
{
|
||||
@@ -3374,7 +3168,7 @@ void GSDrawScanlineCodeGenerator2::ReadTexelImpl(
|
||||
|
||||
void GSDrawScanlineCodeGenerator2::ReadTexelImplLoadTexLOD(int lod, int mip_offset)
|
||||
{
|
||||
AddressReg texIn = is64 ? _64_m_local__gd__tex : t2;
|
||||
AddressReg texIn = _64_m_local__gd__tex;
|
||||
Address lod_addr = m_sel.lcm ? _rip_global(lod.i.U32[lod]) : _rip_local(temp.lod.i.U32[lod]);
|
||||
mov(ebx, lod_addr);
|
||||
mov(rbx, ptr[texIn + rbx * wordsize + mip_offset]);
|
||||
@@ -3392,7 +3186,7 @@ void GSDrawScanlineCodeGenerator2::ReadTexelImplYmm(
|
||||
const Ymm t1[] = { d1, d2s0, d3s1, s2 };
|
||||
const Ymm t2[] = { tmp, tmp, tmp, tmp };
|
||||
|
||||
bool texInRBX = is32;
|
||||
bool texInRBX = false;
|
||||
if (use_lod && m_sel.lcm)
|
||||
{
|
||||
ReadTexelImplLoadTexLOD(0, mip_offset);
|
||||
@@ -3484,7 +3278,7 @@ void GSDrawScanlineCodeGenerator2::ReadTexelImplSSE4(
|
||||
else
|
||||
{
|
||||
bool preserve = false;
|
||||
bool texInRBX = is32;
|
||||
bool texInRBX = false;
|
||||
|
||||
if (use_lod && m_sel.lcm)
|
||||
{
|
||||
@@ -3506,7 +3300,7 @@ void GSDrawScanlineCodeGenerator2::ReadTexelImpl(const Xmm& dst, const Xmm& addr
|
||||
{
|
||||
ASSERT(i < 4);
|
||||
|
||||
AddressReg clut = is64 ? _64_m_local__gd__clut : rdx;
|
||||
AddressReg clut = _64_m_local__gd__clut;
|
||||
AddressReg tex = texInRBX ? rbx : _64_m_local__gd__tex;
|
||||
Address src = m_sel.tlu ? ptr[clut + rax * 4] : ptr[tex + rax * 4];
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class GSDrawScanlineCodeGenerator2 : public GSNewCodeGenerator
|
||||
|
||||
constexpr static bool isXmm = std::is_same<XYm, Xbyak::Xmm>::value;
|
||||
constexpr static bool isYmm = std::is_same<XYm, Xbyak::Ymm>::value;
|
||||
constexpr static int wordsize = is64 ? 8 : 4;
|
||||
constexpr static int wordsize = 8;
|
||||
constexpr static int vecsize = isXmm ? 16 : 32;
|
||||
constexpr static int vecsizelog = isXmm ? 4 : 5;
|
||||
constexpr static int vecints = vecsize / 4;
|
||||
@@ -67,8 +67,7 @@ class GSDrawScanlineCodeGenerator2 : public GSNewCodeGenerator
|
||||
constexpr static int _64_rz_r15 = -8 * 5;
|
||||
constexpr static int _64_top = -8 * 6;
|
||||
#endif
|
||||
constexpr static int _top = is64 ? _64_top : _32_args + 4;
|
||||
constexpr static int _v = is64 ? _invalid : _32_args + 8;
|
||||
constexpr static int _top = _64_top;
|
||||
|
||||
GSScanlineSelector m_sel;
|
||||
GSScanlineLocalData& m_local;
|
||||
|
||||
@@ -100,30 +100,6 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
/// Make sure the register is okay to use
|
||||
void validateRegister(const Operand& op)
|
||||
{
|
||||
if (is64)
|
||||
return;
|
||||
if (op.isREG() && (op.isExtIdx() || op.isExt8bit()))
|
||||
throw Error(Error::ERR_64_BIT_REG_IN_32);
|
||||
if (op.isMEM())
|
||||
{
|
||||
auto e = static_cast<const Address&>(op).getRegExp();
|
||||
validateRegister(e.getIndex());
|
||||
validateRegister(e.getBase());
|
||||
}
|
||||
}
|
||||
/// For easier macro-ing
|
||||
void validateRegister(int imm)
|
||||
{
|
||||
}
|
||||
|
||||
void require64()
|
||||
{
|
||||
if (!is64)
|
||||
throw Error(Error::ERR_64_INSTR_IN_32);
|
||||
}
|
||||
void requireAVX()
|
||||
{
|
||||
if (!hasAVX)
|
||||
@@ -133,9 +109,6 @@ private:
|
||||
public:
|
||||
Xbyak::CodeGenerator& actual;
|
||||
|
||||
#if defined(_M_X86_64)
|
||||
constexpr static bool is32 = false;
|
||||
constexpr static bool is64 = true;
|
||||
using AddressReg = Xbyak::Reg64;
|
||||
using RipType = Xbyak::RegRip;
|
||||
|
||||
@@ -144,18 +117,6 @@ public:
|
||||
|
||||
template <typename T32, typename T64>
|
||||
static T64 choose3264(T32 t32, T64 t64) { return t64; }
|
||||
#else
|
||||
constexpr static bool is32 = true;
|
||||
constexpr static bool is64 = false;
|
||||
using AddressReg = Xbyak::Reg32;
|
||||
using RipType = int;
|
||||
|
||||
template <typename T32, typename T64>
|
||||
struct Choose3264 { using type = T32; };
|
||||
|
||||
template <typename T32, typename T64>
|
||||
static T32 choose3264(T32 t32, T64 t64) { return t32; }
|
||||
#endif
|
||||
|
||||
const bool hasAVX, hasAVX2, hasFMA;
|
||||
|
||||
@@ -238,34 +199,24 @@ public:
|
||||
#define FORWARD1(category, name, type) \
|
||||
void name(type a) \
|
||||
{ \
|
||||
validateRegister(a); \
|
||||
ACTUAL_FORWARD_##category(name, a) \
|
||||
}
|
||||
|
||||
#define FORWARD2(category, name, type1, type2) \
|
||||
void name(type1 a, type2 b) \
|
||||
{ \
|
||||
validateRegister(a); \
|
||||
validateRegister(b); \
|
||||
ACTUAL_FORWARD_##category(name, a, b) \
|
||||
}
|
||||
|
||||
#define FORWARD3(category, name, type1, type2, type3) \
|
||||
void name(type1 a, type2 b, type3 c) \
|
||||
{ \
|
||||
validateRegister(a); \
|
||||
validateRegister(b); \
|
||||
validateRegister(c); \
|
||||
ACTUAL_FORWARD_##category(name, a, b, c) \
|
||||
}
|
||||
|
||||
#define FORWARD4(category, name, type1, type2, type3, type4) \
|
||||
void name(type1 a, type2 b, type3 c, type4 d) \
|
||||
{ \
|
||||
validateRegister(a); \
|
||||
validateRegister(b); \
|
||||
validateRegister(c); \
|
||||
validateRegister(d); \
|
||||
ACTUAL_FORWARD_##category(name, a, b, c, d) \
|
||||
}
|
||||
|
||||
@@ -282,8 +233,6 @@ public:
|
||||
#define FORWARD_SSE_XMM0(name) \
|
||||
void name(const Xmm& a, const Operand& b) \
|
||||
{ \
|
||||
validateRegister(a); \
|
||||
validateRegister(b); \
|
||||
if (hasAVX) \
|
||||
actual.v##name(a, b, Xmm(0)); \
|
||||
else \
|
||||
@@ -326,19 +275,12 @@ public:
|
||||
#define ARGS_XOI const Xmm&, const Operand&, u8
|
||||
#define ARGS_XXO const Xmm&, const Xmm&, const Operand&
|
||||
|
||||
// For instructions that are ifdef'd out without XBYAK64
|
||||
#ifdef XBYAK64
|
||||
#define REQUIRE64(action) require64(); action
|
||||
#else
|
||||
#define REQUIRE64(action) require64()
|
||||
#endif
|
||||
|
||||
const u8 *getCurr() { return actual.getCurr(); }
|
||||
void align(int x = 16) { return actual.align(x); }
|
||||
void db(int code) { actual.db(code); }
|
||||
void L(const std::string& label) { actual.L(label); }
|
||||
|
||||
void cdqe() { REQUIRE64(actual.cdqe()); }
|
||||
void cdqe() { actual.cdqe(); }
|
||||
void ret(int imm = 0) { actual.ret(imm); }
|
||||
void vzeroupper() { requireAVX(); actual.vzeroupper(); }
|
||||
void vzeroall() { requireAVX(); actual.vzeroall(); }
|
||||
@@ -458,7 +400,6 @@ public:
|
||||
FORWARD(3, AVX2, vpsravd, ARGS_XXO)
|
||||
FORWARD(3, AVX2, vpsrlvd, ARGS_XXO)
|
||||
|
||||
#undef REQUIRE64
|
||||
#undef ARGS_OI
|
||||
#undef ARGS_OO
|
||||
#undef ARGS_XI
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSRasterizer.h"
|
||||
#include "GS/GSExtra.h"
|
||||
#include "PerformanceMetrics.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/PersistentThread.h"
|
||||
|
||||
#define ENABLE_DRAW_STATS 0
|
||||
|
||||
int GSRasterizerData::s_counter = 0;
|
||||
|
||||
@@ -128,8 +133,6 @@ int GSRasterizer::GetPixels(bool reset)
|
||||
|
||||
void GSRasterizer::Draw(GSRasterizerData* data)
|
||||
{
|
||||
GSPerfMonAutoTimer pmat(m_perfmon, GSPerfMon::WorkerDraw0 + m_id);
|
||||
|
||||
if (data->vertex != NULL && data->vertex_count == 0 || data->index != NULL && data->index_count == 0)
|
||||
return;
|
||||
|
||||
@@ -137,7 +140,8 @@ void GSRasterizer::Draw(GSRasterizerData* data)
|
||||
m_pixels.total = 0;
|
||||
m_primcount = 0;
|
||||
|
||||
data->start = __rdtsc();
|
||||
if constexpr (ENABLE_DRAW_STATS)
|
||||
data->start = __rdtsc();
|
||||
|
||||
m_ds->BeginDraw(data);
|
||||
|
||||
@@ -244,11 +248,10 @@ void GSRasterizer::Draw(GSRasterizerData* data)
|
||||
|
||||
data->pixels = m_pixels.actual;
|
||||
|
||||
u64 ticks = __rdtsc() - data->start;
|
||||
|
||||
m_pixels.sum += m_pixels.actual;
|
||||
|
||||
m_ds->EndDraw(data->frame, ticks, m_pixels.actual, m_pixels.total, m_primcount);
|
||||
if constexpr (ENABLE_DRAW_STATS)
|
||||
m_ds->EndDraw(data->frame, __rdtsc() - data->start, m_pixels.actual, m_pixels.total, m_primcount);
|
||||
}
|
||||
|
||||
template <bool scissor_test>
|
||||
@@ -1190,13 +1193,27 @@ GSRasterizerList::GSRasterizerList(int threads, GSPerfMon* perfmon)
|
||||
{
|
||||
m_scanline[i] = static_cast<u8>(i % threads);
|
||||
}
|
||||
|
||||
PerformanceMetrics::SetGSSWThreadCount(threads);
|
||||
}
|
||||
|
||||
GSRasterizerList::~GSRasterizerList()
|
||||
{
|
||||
PerformanceMetrics::SetGSSWThreadCount(0);
|
||||
_aligned_free(m_scanline);
|
||||
}
|
||||
|
||||
void GSRasterizerList::OnWorkerStartup(int i)
|
||||
{
|
||||
Threading::SetNameOfCurrentThread(StringUtil::StdStringFromFormat("GS-SW-%d", i).c_str());
|
||||
PerformanceMetrics::SetGSSWThreadTimer(i, Common::ThreadCPUTimer::GetForCallingThread());
|
||||
}
|
||||
|
||||
void GSRasterizerList::OnWorkerShutdown(int i)
|
||||
{
|
||||
PerformanceMetrics::SetGSSWThreadTimer(i, Common::ThreadCPUTimer());
|
||||
}
|
||||
|
||||
void GSRasterizerList::Queue(const GSRingHeap::SharedPtr<GSRasterizerData>& data)
|
||||
{
|
||||
GSVector4i r = data->bbox.rintersect(data->scissor);
|
||||
|
||||
@@ -197,6 +197,9 @@ protected:
|
||||
|
||||
GSRasterizerList(int threads, GSPerfMon* perfmon);
|
||||
|
||||
void OnWorkerStartup(int i);
|
||||
void OnWorkerShutdown(int i);
|
||||
|
||||
public:
|
||||
virtual ~GSRasterizerList();
|
||||
|
||||
@@ -217,7 +220,9 @@ public:
|
||||
rl->m_r.push_back(std::unique_ptr<GSRasterizer>(new GSRasterizer(new DS(), i, threads, perfmon)));
|
||||
auto& r = *rl->m_r[i];
|
||||
rl->m_workers.push_back(std::unique_ptr<GSWorker>(new GSWorker(
|
||||
[&r](GSRingHeap::SharedPtr<GSRasterizerData>& item) { r.Draw(item.get()); })));
|
||||
[rl, i]() { rl->OnWorkerStartup(i); },
|
||||
[&r](GSRingHeap::SharedPtr<GSRasterizerData>& item) { r.Draw(item.get()); },
|
||||
[rl, i]() { rl->OnWorkerShutdown(i); })));
|
||||
}
|
||||
|
||||
return rl;
|
||||
|
||||
@@ -58,14 +58,6 @@ GSRendererSW::GSRendererSW(int threads)
|
||||
InitCVB(GS_SPRITE_CLASS);
|
||||
|
||||
m_dump_root = root_sw;
|
||||
|
||||
// Reset handler with the auto flush hack enabled on the SW renderer.
|
||||
// Some games run better without the hack so rely on ini/gui option.
|
||||
if (theApp.GetConfigB("autoflush_sw"))
|
||||
{
|
||||
m_userhacks_auto_flush = true;
|
||||
ResetHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
GSRendererSW::~GSRendererSW()
|
||||
@@ -325,6 +317,24 @@ void GSRendererSW::Draw()
|
||||
{
|
||||
const GSDrawingContext* context = m_context;
|
||||
|
||||
if (s_dump)
|
||||
{
|
||||
std::string s;
|
||||
|
||||
if (s_n >= s_saven)
|
||||
{
|
||||
// Dump Register state
|
||||
s = format("%05d_context.txt", s_n);
|
||||
|
||||
m_env.Dump(m_dump_root + s);
|
||||
m_context->Dump(m_dump_root + s);
|
||||
|
||||
// Dump vertices
|
||||
s = format("%05d_vertex.txt", s_n);
|
||||
DumpVertices(m_dump_root + s);
|
||||
}
|
||||
}
|
||||
|
||||
auto data = m_vertex_heap.make_shared<SharedData>(this).cast<GSRasterizerData>();
|
||||
SharedData* sd = static_cast<SharedData*>(data.get());
|
||||
|
||||
@@ -434,22 +444,13 @@ void GSRendererSW::Draw()
|
||||
{
|
||||
Sync(2);
|
||||
|
||||
std::string s;
|
||||
|
||||
u64 frame = g_perfmon.GetFrame();
|
||||
// Dump the texture in 32 bits format. It helps to debug texture shuffle effect
|
||||
// It will breaks the few games that really uses 16 bits RT
|
||||
bool texture_shuffle = ((context->FRAME.PSM & 0x2) && ((context->TEX0.PSM & 3) == 2) && (m_vt.m_primclass == GS_SPRITE_CLASS));
|
||||
|
||||
std::string s;
|
||||
|
||||
if (s_n >= s_saven)
|
||||
{
|
||||
// Dump Register state
|
||||
s = format("%05d_context.txt", s_n);
|
||||
|
||||
m_env.Dump(m_dump_root + s);
|
||||
m_context->Dump(m_dump_root + s);
|
||||
}
|
||||
|
||||
if (s_savet && s_n >= s_saven && PRIM->TME)
|
||||
{
|
||||
if (texture_shuffle)
|
||||
@@ -581,9 +582,7 @@ void GSRendererSW::Sync(int reason)
|
||||
{
|
||||
//printf("sync %d\n", reason);
|
||||
|
||||
GSPerfMonAutoTimer pmat(&g_perfmon, GSPerfMon::Sync);
|
||||
|
||||
u64 t = __rdtsc();
|
||||
u64 t = LOG ? __rdtsc() : 0;
|
||||
|
||||
m_rl->Sync();
|
||||
|
||||
@@ -606,7 +605,7 @@ void GSRendererSW::Sync(int reason)
|
||||
}
|
||||
}
|
||||
|
||||
t = __rdtsc() - t;
|
||||
t = LOG ? (__rdtsc() - t) : 0;
|
||||
|
||||
int pixels = m_rl->GetPixels();
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
using namespace Xbyak;
|
||||
|
||||
#define _rip_local(field) ((is32 || m_rip) ? ptr[rip + (char*)&m_local.field] : ptr[_m_local + OFFSETOF(GSScanlineLocalData, field)])
|
||||
#define _rip_local(field) ((m_rip) ? ptr[rip + (char*)&m_local.field] : ptr[_m_local + OFFSETOF(GSScanlineLocalData, field)])
|
||||
|
||||
#define _64_m_local _64_t0
|
||||
|
||||
@@ -53,15 +53,15 @@ GSSetupPrimCodeGenerator2::GSSetupPrimCodeGenerator2(Xbyak::CodeGenerator* base,
|
||||
, m_rip(false), many_regs(false)
|
||||
// On x86 arg registers are very temporary but on x64 they aren't, so on x86 some registers overlap
|
||||
#ifdef _WIN32
|
||||
, _64_vertex(is64 ? rcx : r8)
|
||||
, _index(is64 ? rdx : rcx)
|
||||
, _dscan(is64 ? r8 : rdx)
|
||||
, _64_t0(r9), t1(is64 ? r10 : rcx)
|
||||
, _64_vertex(rcx)
|
||||
, _index(rdx)
|
||||
, _dscan(r8)
|
||||
, _64_t0(r9), t1(r10)
|
||||
#else
|
||||
, _64_vertex(is64 ? rdi : r8)
|
||||
, _index(is64 ? rsi : rcx)
|
||||
, _64_vertex(rdi)
|
||||
, _index(rsi)
|
||||
, _dscan(rdx)
|
||||
, _64_t0(is64 ? rcx : r8), t1(is64 ? r8 : rcx)
|
||||
, _64_t0(rcx), t1(r8)
|
||||
#endif
|
||||
, _m_local(chooseLocal(&m_local, _64_m_local))
|
||||
{
|
||||
@@ -88,7 +88,7 @@ void GSSetupPrimCodeGenerator2::Generate()
|
||||
m_rip = (size_t)&m_local < 0x80000000 && (size_t)getCurr() < 0x80000000;
|
||||
|
||||
bool needs_shift = (m_en.z || m_en.f) && m_sel.prim != GS_SPRITE_CLASS || m_en.t || m_en.c && m_sel.iip;
|
||||
many_regs = is64 && isYmm && !m_sel.notest && needs_shift;
|
||||
many_regs = isYmm && !m_sel.notest && needs_shift;
|
||||
|
||||
#ifdef _WIN64
|
||||
int needs_saving = many_regs ? 6 : m_sel.notest ? 0 : 2;
|
||||
@@ -102,13 +102,11 @@ void GSSetupPrimCodeGenerator2::Generate()
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is64 && !m_rip)
|
||||
if (!m_rip)
|
||||
mov(_64_m_local, (size_t)&m_local);
|
||||
|
||||
if (needs_shift)
|
||||
{
|
||||
if (is32)
|
||||
mov(_dscan, ptr[rsp + _32_dscan]);
|
||||
|
||||
if (isXmm)
|
||||
mov(rax, (size_t)g_const->m_shift_128b);
|
||||
@@ -193,14 +191,9 @@ void GSSetupPrimCodeGenerator2::Depth_XMM()
|
||||
if (m_sel.prim != GS_POINT_CLASS)
|
||||
offset = sizeof(u32) * 1;
|
||||
|
||||
if (is32)
|
||||
mov(_index, ptr[rsp + _32_index]);
|
||||
mov(eax, ptr[_index + offset]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
if (is64)
|
||||
add(rax, _64_vertex);
|
||||
else
|
||||
add(rax, ptr[rsp + _32_vertex]);
|
||||
add(rax, _64_vertex);
|
||||
|
||||
movdqa(xmm0, ptr[rax + offsetof(GSVertexSW, t)]);
|
||||
pshufd(xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
@@ -231,14 +224,9 @@ void GSSetupPrimCodeGenerator2::Depth_XMM()
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
if (is32)
|
||||
mov(_index, ptr[rsp + _32_index]);
|
||||
mov(eax, ptr[_index + sizeof(u32) * 1]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
if (is64)
|
||||
add(rax, _64_vertex);
|
||||
else
|
||||
add(rax, ptr[rsp + _32_vertex]);
|
||||
add(rax, _64_vertex);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
@@ -285,14 +273,9 @@ void GSSetupPrimCodeGenerator2::Depth_YMM()
|
||||
if (m_sel.prim != GS_POINT_CLASS)
|
||||
offset = sizeof(u32) * 1;
|
||||
|
||||
if (is32)
|
||||
mov(_index, ptr[rsp + _32_index]);
|
||||
mov(eax, ptr[_index + offset]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
if (is64)
|
||||
add(rax, _64_vertex);
|
||||
else
|
||||
add(rax, ptr[rsp + _32_vertex]);
|
||||
add(rax, _64_vertex);
|
||||
|
||||
mov(t1.cvt32(), ptr[rax + offsetof(GSVertexSW, t.w)]);
|
||||
mov(_rip_local(p.z), t1.cvt32());
|
||||
@@ -354,14 +337,9 @@ void GSSetupPrimCodeGenerator2::Depth_YMM()
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
if (is32)
|
||||
mov(_index, ptr[rsp + _32_index]);
|
||||
mov(eax, ptr[_index + sizeof(u32) * 1]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
if (is64)
|
||||
add(rax, _64_vertex);
|
||||
else
|
||||
add(rax, ptr[rsp + _32_vertex]);
|
||||
add(rax, _64_vertex);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
@@ -564,14 +542,9 @@ void GSSetupPrimCodeGenerator2::Color()
|
||||
|
||||
if (!(m_sel.prim == GS_SPRITE_CLASS && (m_en.z || m_en.f))) // if this is a sprite, the last vertex was already loaded in Depth()
|
||||
{
|
||||
if (is32)
|
||||
mov(_index, ptr[rsp + _32_index]);
|
||||
mov(eax, ptr[_index + sizeof(u32) * last]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
if (is64)
|
||||
add(rax, _64_vertex);
|
||||
else
|
||||
add(rax, ptr[rsp + _32_vertex]);
|
||||
add(rax, _64_vertex);
|
||||
}
|
||||
|
||||
if (isXmm)
|
||||
|
||||
@@ -46,12 +46,6 @@ class GSSetupPrimCodeGenerator2 : public GSNewCodeGenerator
|
||||
|
||||
constexpr static int dsize = isXmm ? 4 : 8;
|
||||
|
||||
constexpr static int _32_args = 0;
|
||||
constexpr static int _invalid = 0xaaaaaaaa;
|
||||
constexpr static int _32_vertex = is64 ? _invalid : _32_args + 4;
|
||||
constexpr static int _32_index = is64 ? _invalid : _32_args + 8;
|
||||
constexpr static int _32_dscan = is64 ? _invalid : _32_args + 12;
|
||||
|
||||
GSScanlineSelector m_sel;
|
||||
GSScanlineLocalData& m_local;
|
||||
bool m_rip;
|
||||
|
||||
@@ -2769,11 +2769,25 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
const bool render_area_okay =
|
||||
(!hdr_rt && DATE_rp != DATE_RENDER_PASS_STENCIL_ONE && CheckRenderPassArea(render_area));
|
||||
const bool same_framebuffer =
|
||||
(InRenderPass() && m_current_render_target == draw_rt && m_current_depth_target == draw_ds);
|
||||
|
||||
// Prefer keeping feedback loop enabled, that way we're not constantly restarting render passes
|
||||
pipe.feedback_loop |= render_area_okay && same_framebuffer && CurrentFramebufferHasFeedbackLoop();
|
||||
// render pass restart optimizations
|
||||
if (render_area_okay)
|
||||
{
|
||||
// avoid restarting the render pass just to switch from rt+depth to rt and vice versa
|
||||
if (!draw_ds && m_current_depth_target && m_current_render_target == draw_rt &&
|
||||
config.tex != m_current_depth_target && !(pipe.feedback_loop && !CurrentFramebufferHasFeedbackLoop()))
|
||||
{
|
||||
draw_ds = m_current_depth_target;
|
||||
m_pipeline_selector.ds = true;
|
||||
m_pipeline_selector.dss.ztst = ZTST_ALWAYS;
|
||||
m_pipeline_selector.dss.zwe = false;
|
||||
}
|
||||
|
||||
// Prefer keeping feedback loop enabled, that way we're not constantly restarting render passes
|
||||
pipe.feedback_loop |= m_current_render_target == draw_rt && m_current_depth_target == draw_ds &&
|
||||
CurrentFramebufferHasFeedbackLoop();
|
||||
}
|
||||
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, pipe.feedback_loop);
|
||||
if (pipe.feedback_loop)
|
||||
PSSetShaderResource(2, draw_rt, false);
|
||||
|
||||
@@ -55,9 +55,9 @@ const char* dialog_message(int ID, bool* updateText)
|
||||
"Aggressive:\nUse more aggressive CRC hacks.\n"
|
||||
"Removes effects in some games which make the image appear sharper/clearer.\n"
|
||||
"Affected games: AC4, BleachBB, Bully, DBZBT 2 & 3, DeathByDegrees, Evangelion, FF games, FightingBeautyWulong, GOW 1 & 2, Kunoichi, IkkiTousen, Okami, Oneechanbara2, OnimushaDoD, RDRevolver, Simple2000Vol114, SoTC, SteambotChronicles, Tekken5, Ultraman, XenosagaE3, Yakuza 1 & 2.\n");
|
||||
case IDC_SKIPDRAWHACK:
|
||||
case IDC_SKIPDRAWEND:
|
||||
case IDC_SKIPDRAWHACKEDIT:
|
||||
case IDC_SKIPDRAWOFFSET:
|
||||
case IDC_SKIPDRAWSTART:
|
||||
case IDC_SKIPDRAWOFFSETEDIT:
|
||||
return cvtString("Completely skips drawing surfaces from the surface in the left box up to the surface specified in the box on the right.\n\n"
|
||||
"Use it, for example, to try and get rid of bad post processing effects.\n"
|
||||
@@ -177,7 +177,7 @@ const char* dialog_message(int ID, bool* updateText)
|
||||
"Off:\nMipmapping emulation is disabled.\n\n"
|
||||
"Basic (Fast):\nPartially emulates mipmapping, performance impact is negligible in most cases.\n\n"
|
||||
"Full (Slow):\nCompletely emulates the mipmapping function of the GS, might significantly impact performance.");
|
||||
case IDC_FAST_TC_INV:
|
||||
case IDC_DISABLE_PARTIAL_TC_INV:
|
||||
return cvtString("By default, the texture cache handles partial invalidations. Unfortunately it is very costly to compute CPU wise."
|
||||
"\n\nThis hack replaces the partial invalidation with a complete deletion of the texture to reduce the CPU load.\n\nIt helps snowblind engine games.");
|
||||
case IDC_CONSERVATIVE_FB:
|
||||
|
||||
@@ -56,15 +56,15 @@ enum
|
||||
IDC_AUTO_FLUSH_HW,
|
||||
IDC_TC_DEPTH,
|
||||
IDC_SAFE_FEATURES,
|
||||
IDC_FAST_TC_INV,
|
||||
IDC_DISABLE_PARTIAL_TC_INV,
|
||||
IDC_CPU_FB_CONVERSION,
|
||||
IDC_MEMORY_WRAPPING,
|
||||
IDC_PRELOAD_GS,
|
||||
IDC_HALF_SCREEN_TS,
|
||||
IDC_TRI_FILTER,
|
||||
IDC_SKIPDRAWHACK,
|
||||
IDC_SKIPDRAWEND,
|
||||
IDC_SKIPDRAWHACKEDIT,
|
||||
IDC_SKIPDRAWOFFSET,
|
||||
IDC_SKIPDRAWSTART,
|
||||
IDC_SKIPDRAWOFFSETEDIT,
|
||||
IDC_TEX_IN_RT,
|
||||
// Upscaling Hacks
|
||||
|
||||
@@ -290,12 +290,12 @@ RendererTab::RendererTab(wxWindow* parent)
|
||||
|
||||
m_internal_resolution = m_ui.addComboBoxAndLabel(hw_choice_grid, "Internal Resolution:", "upscale_multiplier", &theApp.m_gs_upscale_multiplier, -1, hw_prereq).first;
|
||||
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Anisotropic Filtering:", "MaxAnisotropy", &theApp.m_gs_max_anisotropy, IDC_AFCOMBO, aniso_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Dithering (PgDn):", "dithering_ps2", &theApp.m_gs_dithering, IDC_DITHERING, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Mipmapping:", "mipmap_hw", &theApp.m_gs_hw_mipmapping, IDC_MIPMAP_HW, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "CRC Hack Level:", "crc_hack_level", &theApp.m_gs_crc_level, IDC_CRC_LEVEL, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Blending Accuracy:", "accurate_blending_unit", &theApp.m_gs_acc_blend_level, IDC_ACCURATE_BLEND_UNIT, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Texture Preloading:", "texture_preloading", &theApp.m_gs_texture_preloading, IDC_PRELOAD_TEXTURES, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Anisotropic Filtering:", "MaxAnisotropy", &theApp.m_gs_max_anisotropy, IDC_AFCOMBO, aniso_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Dithering (PgDn):", "dithering_ps2", &theApp.m_gs_dithering, IDC_DITHERING, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Mipmapping:", "mipmap_hw", &theApp.m_gs_hw_mipmapping, IDC_MIPMAP_HW, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "CRC Hack Level:", "crc_hack_level", &theApp.m_gs_crc_level, IDC_CRC_LEVEL, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Blending Accuracy:", "accurate_blending_unit", &theApp.m_gs_acc_blend_level, IDC_ACCURATE_BLEND_UNIT, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Texture Preloading:", "texture_preloading", &theApp.m_gs_texture_preloading, IDC_PRELOAD_TEXTURES, hw_prereq);
|
||||
|
||||
hardware_box->Add(hw_checks_box, wxSizerFlags().Centre());
|
||||
hardware_box->AddSpacer(space);
|
||||
@@ -328,7 +328,7 @@ HacksTab::HacksTab(wxWindow* parent)
|
||||
PaddedBoxSizer<wxBoxSizer> tab_box(wxVERTICAL);
|
||||
|
||||
auto hw_prereq = [this]{ return m_is_hardware; };
|
||||
auto* hacks_check_box = m_ui.addCheckBox(tab_box.inner, "Enable HW Hacks", "UserHacks", -1, hw_prereq);
|
||||
auto* hacks_check_box = m_ui.addCheckBox(tab_box.inner, "Manual HW Hacks", "UserHacks", -1, hw_prereq);
|
||||
auto hacks_prereq = [this, hacks_check_box]{ return m_is_hardware && hacks_check_box->GetValue(); };
|
||||
auto upscale_hacks_prereq = [this, hacks_check_box]{ return !m_is_native_res && hacks_check_box->GetValue(); };
|
||||
|
||||
@@ -339,14 +339,14 @@ HacksTab::HacksTab(wxWindow* parent)
|
||||
auto* upscale_hacks_grid = new wxFlexGridSizer(3, space, space);
|
||||
|
||||
// Renderer Hacks
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Auto Flush", "UserHacks_AutoFlush", IDC_AUTO_FLUSH_HW, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Frame Buffer Conversion", "UserHacks_CPU_FB_Conversion", IDC_CPU_FB_CONVERSION, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Disable Depth Emulation", "UserHacks_DisableDepthSupport", IDC_TC_DEPTH, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Memory Wrapping", "wrap_gs_mem", IDC_MEMORY_WRAPPING, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Disable Safe Features", "UserHacks_Disable_Safe_Features", IDC_SAFE_FEATURES, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Preload Frame Data", "preload_frame_with_gs_data", IDC_PRELOAD_GS, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Fast Texture Invalidation", "UserHacks_DisablePartialInvalidation", IDC_FAST_TC_INV, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Texture Inside RT", "UserHacks_TextureInsideRt", IDC_TEX_IN_RT, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Auto Flush", "UserHacks_AutoFlush", IDC_AUTO_FLUSH_HW, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Frame Buffer Conversion", "UserHacks_CPU_FB_Conversion", IDC_CPU_FB_CONVERSION, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Disable Depth Emulation", "UserHacks_DisableDepthSupport", IDC_TC_DEPTH, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Memory Wrapping", "wrap_gs_mem", IDC_MEMORY_WRAPPING, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Disable Safe Features", "UserHacks_Disable_Safe_Features", IDC_SAFE_FEATURES, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Preload Frame Data", "preload_frame_with_gs_data", IDC_PRELOAD_GS, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Disable Partial Invalidation", "UserHacks_DisablePartialInvalidation", IDC_DISABLE_PARTIAL_TC_INV, hacks_prereq);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Texture Inside RT", "UserHacks_TextureInsideRt", IDC_TEX_IN_RT, hacks_prereq);
|
||||
|
||||
// Upscale
|
||||
m_ui.addCheckBox(upscale_hacks_grid, "Align Sprite", "UserHacks_align_sprite_X", IDC_ALIGN_SPRITE, upscale_hacks_prereq);
|
||||
@@ -363,10 +363,10 @@ HacksTab::HacksTab(wxWindow* parent)
|
||||
m_ui.addComboBoxAndLabel(rend_hack_choice_grid, "Trilinear Filtering:", "UserHacks_TriFilter", &theApp.m_gs_trifilter, IDC_TRI_FILTER, hacks_prereq);
|
||||
|
||||
// Skipdraw Range
|
||||
add_label(this, rend_hack_choice_grid, "Skipdraw Range:", IDC_SKIPDRAWHACK);
|
||||
add_label(this, rend_hack_choice_grid, "Skipdraw Range:", IDC_SKIPDRAWEND);
|
||||
auto* skip_box = new wxBoxSizer(wxHORIZONTAL);
|
||||
skip_x_spin = m_ui.addSpin(skip_box, "UserHacks_SkipDraw_Offset", 0, 10000, 0, IDC_SKIPDRAWOFFSET, hacks_prereq);
|
||||
skip_y_spin = m_ui.addSpin(skip_box, "UserHacks_SkipDraw", 0, 10000, 0, IDC_SKIPDRAWHACK, hacks_prereq);
|
||||
skip_x_spin = m_ui.addSpin(skip_box, "UserHacks_SkipDraw_Start", 0, 10000, 0, IDC_SKIPDRAWSTART, hacks_prereq);
|
||||
skip_y_spin = m_ui.addSpin(skip_box, "UserHacks_SkipDraw_End", 0, 10000, 0, IDC_SKIPDRAWEND, hacks_prereq);
|
||||
|
||||
rend_hack_choice_grid->Add(skip_box, wxSizerFlags().Expand());
|
||||
|
||||
@@ -513,12 +513,13 @@ OSDTab::OSDTab(wxWindow* parent)
|
||||
auto* log_grid = new wxFlexGridSizer(2, space, space);
|
||||
log_grid->AddGrowableCol(1);
|
||||
|
||||
m_ui.addCheckBox(log_grid, "Show Messages", "OsdShowMessages", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show Speed", "OsdShowSpeed", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show FPS", "OsdShowFPS", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show CPU Usage", "OsdShowCPU", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show Messages", "OsdShowMessages", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show Speed", "OsdShowSpeed", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show FPS", "OsdShowFPS", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show CPU Usage", "OsdShowCPU", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show GPU Usage", "OsdShowGPU", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show Resolution", "OsdShowResolution", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show Statistics", "OsdShowGSStats", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show Statistics", "OsdShowGSStats", -1);
|
||||
m_ui.addCheckBox(log_grid, "Show Indicators", "OsdShowIndicators", -1);
|
||||
|
||||
log_box->Add(log_grid, wxSizerFlags().Expand());
|
||||
@@ -540,10 +541,10 @@ DebugTab::DebugTab(wxWindow* parent)
|
||||
{
|
||||
PaddedBoxSizer<wxStaticBoxSizer> debug_box(wxVERTICAL, this, "Debug");
|
||||
auto* debug_check_box = new wxWrapSizer(wxHORIZONTAL);
|
||||
m_ui.addCheckBox(debug_check_box, "Use Blit Swap Chain", "UseBlitSwapChain");
|
||||
m_ui.addCheckBox(debug_check_box, "Use Blit Swap Chain", "UseBlitSwapChain");
|
||||
m_ui.addCheckBox(debug_check_box, "Disable Shader Cache", "disable_shader_cache");
|
||||
m_ui.addCheckBox(debug_check_box, "Use Debug Device", "UseDebugDevice");
|
||||
m_ui.addCheckBox(debug_check_box, "Dump GS data", "dump");
|
||||
m_ui.addCheckBox(debug_check_box, "Use Debug Device", "UseDebugDevice");
|
||||
m_ui.addCheckBox(debug_check_box, "Dump GS data", "dump");
|
||||
|
||||
auto* debug_save_check_box = new wxWrapSizer(wxHORIZONTAL);
|
||||
m_ui.addCheckBox(debug_save_check_box, "Save RT", "save");
|
||||
@@ -576,12 +577,12 @@ DebugTab::DebugTab(wxWindow* parent)
|
||||
|
||||
PaddedBoxSizer<wxStaticBoxSizer> tex_box(wxVERTICAL, this, "Texture Replacements");
|
||||
auto* tex_grid = new wxFlexGridSizer(2, space, space);
|
||||
m_ui.addCheckBox(tex_grid, "Dump Textures", "DumpReplaceableTextures", -1);
|
||||
m_ui.addCheckBox(tex_grid, "Dump Mipmaps", "DumpReplaceableMipmaps", -1);
|
||||
m_ui.addCheckBox(tex_grid, "Dump FMV Textures", "DumpTexturesWithFMVActive", -1);
|
||||
m_ui.addCheckBox(tex_grid, "Dump Textures", "DumpReplaceableTextures", -1);
|
||||
m_ui.addCheckBox(tex_grid, "Dump Mipmaps", "DumpReplaceableMipmaps", -1);
|
||||
m_ui.addCheckBox(tex_grid, "Dump FMV Textures", "DumpTexturesWithFMVActive", -1);
|
||||
m_ui.addCheckBox(tex_grid, "Async Texture Loading", "LoadTextureReplacementsAsync", -1);
|
||||
m_ui.addCheckBox(tex_grid, "Load Textures", "LoadTextureReplacements", -1);
|
||||
m_ui.addCheckBox(tex_grid, "Precache Textures", "PrecacheTextureReplacements", -1);
|
||||
m_ui.addCheckBox(tex_grid, "Load Textures", "LoadTextureReplacements", -1);
|
||||
m_ui.addCheckBox(tex_grid, "Precache Textures", "PrecacheTextureReplacements", -1);
|
||||
tex_box->Add(tex_grid);
|
||||
|
||||
tab_box->Add(tex_box.outer, wxSizerFlags().Expand());
|
||||
@@ -626,11 +627,11 @@ Dialog::Dialog()
|
||||
m_debug_panel = new DebugTab(book);
|
||||
|
||||
book->AddPage(m_renderer_panel, "Renderer", true);
|
||||
book->AddPage(m_hacks_panel, "Hacks");
|
||||
book->AddPage(m_post_panel, "Shader");
|
||||
book->AddPage(m_osd_panel, "OSD");
|
||||
book->AddPage(m_rec_panel, "Recording");
|
||||
book->AddPage(m_debug_panel, "Advanced");
|
||||
book->AddPage(m_hacks_panel, "Hacks");
|
||||
book->AddPage(m_post_panel, "Shader");
|
||||
book->AddPage(m_osd_panel, "OSD");
|
||||
book->AddPage(m_rec_panel, "Recording");
|
||||
book->AddPage(m_debug_panel, "Advanced");
|
||||
|
||||
m_top_box->Add(top_grid, wxSizerFlags().Centre());
|
||||
m_top_box->AddSpacer(space);
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Timer.h"
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
// Has to come before Gif.h
|
||||
#include "MemoryTypes.h"
|
||||
|
||||
#include "Frontend/ImGuiManager.h"
|
||||
#include "Frontend/GameList.h"
|
||||
#include "Gif.h"
|
||||
#include "Gif_Unit.h"
|
||||
#include "GSDumpReplayer.h"
|
||||
#include "GS/GSLzma.h"
|
||||
#include "GS.h"
|
||||
#include "Host.h"
|
||||
#include "R3000A.h"
|
||||
#include "R5900.h"
|
||||
#include "VMManager.h"
|
||||
#include "VUmicro.h"
|
||||
|
||||
static void GSDumpReplayerCpuReserve();
|
||||
static void GSDumpReplayerCpuShutdown();
|
||||
static void GSDumpReplayerCpuReset();
|
||||
static void GSDumpReplayerCpuStep();
|
||||
static void GSDumpReplayerCpuExecute();
|
||||
static void GSDumpReplayerCpuCheckExecutionState();
|
||||
static void GSDumpReplayerCpuThrowException(const BaseException& ex);
|
||||
static void GSDumpReplayerCpuThrowCpuException(const BaseR5900Exception& ex);
|
||||
static void GSDumpReplayerCpuClear(u32 addr, u32 size);
|
||||
static uint GSDumpReplayerCpuGetCacheReserve();
|
||||
static void GSDumpReplayerCpuSetCacheReserve(uint reserveInMegs);
|
||||
|
||||
static std::unique_ptr<GSDumpFile> s_dump_file;
|
||||
static u32 s_current_packet = 0;
|
||||
static u32 s_dump_frame_number = 0;
|
||||
static bool s_dump_running = false;
|
||||
static bool s_needs_state_loaded = false;
|
||||
static u64 s_frame_ticks = 0;
|
||||
static u64 s_next_frame_time = 0;
|
||||
|
||||
R5900cpu GSDumpReplayerCpu = {
|
||||
GSDumpReplayerCpuReserve,
|
||||
GSDumpReplayerCpuShutdown,
|
||||
GSDumpReplayerCpuReset,
|
||||
GSDumpReplayerCpuStep,
|
||||
GSDumpReplayerCpuExecute,
|
||||
GSDumpReplayerCpuCheckExecutionState,
|
||||
GSDumpReplayerCpuThrowException,
|
||||
GSDumpReplayerCpuThrowCpuException,
|
||||
GSDumpReplayerCpuClear,
|
||||
GSDumpReplayerCpuGetCacheReserve,
|
||||
GSDumpReplayerCpuSetCacheReserve};
|
||||
|
||||
static InterpVU0 gsDumpVU0;
|
||||
static InterpVU1 gsDumpVU1;
|
||||
|
||||
bool GSDumpReplayer::IsReplayingDump()
|
||||
{
|
||||
return static_cast<bool>(s_dump_file);
|
||||
}
|
||||
|
||||
bool GSDumpReplayer::Initialize(const char* filename)
|
||||
{
|
||||
Common::Timer timer;
|
||||
Console.WriteLn("(GSDumpReplayer) Reading file...");
|
||||
|
||||
s_dump_file = GSDumpFile::OpenGSDump(filename);
|
||||
if (!s_dump_file || !s_dump_file->ReadFile())
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("GSDumpReplayer", "Failed to open or read '%s'.", filename);
|
||||
s_dump_file.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLn("(GSDumpReplayer) Read file in %.2f ms.", timer.GetTimeMilliseconds());
|
||||
|
||||
// We replace all CPUs.
|
||||
Cpu = &GSDumpReplayerCpu;
|
||||
psxCpu = &psxInt;
|
||||
CpuVU0 = &gsDumpVU0;
|
||||
CpuVU1 = &gsDumpVU1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSDumpReplayer::Reset()
|
||||
{
|
||||
GSDumpReplayerCpuReset();
|
||||
}
|
||||
|
||||
void GSDumpReplayer::Shutdown()
|
||||
{
|
||||
Console.WriteLn("(GSDumpReplayer) Shutting down.");
|
||||
|
||||
Cpu = nullptr;
|
||||
psxCpu = nullptr;
|
||||
CpuVU0 = nullptr;
|
||||
CpuVU1 = nullptr;
|
||||
s_dump_file.reset();
|
||||
}
|
||||
|
||||
std::string GSDumpReplayer::GetDumpSerial()
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
if (!s_dump_file->GetSerial().empty())
|
||||
{
|
||||
ret = s_dump_file->GetSerial();
|
||||
}
|
||||
else if (s_dump_file->GetCRC() != 0)
|
||||
{
|
||||
// old dump files don't have serials, but we have the crc...
|
||||
// so, let's try searching the game list for a crc match.
|
||||
auto lock = GameList::GetLock();
|
||||
const GameList::Entry* entry = GameList::GetEntryByCRC(s_dump_file->GetCRC());
|
||||
if (entry)
|
||||
ret = entry->serial;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 GSDumpReplayer::GetDumpCRC()
|
||||
{
|
||||
return s_dump_file->GetCRC();
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuReserve()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuReset()
|
||||
{
|
||||
s_needs_state_loaded = true;
|
||||
s_current_packet = 0;
|
||||
s_dump_frame_number = 0;
|
||||
}
|
||||
|
||||
static void GSDumpReplayerLoadInitialState()
|
||||
{
|
||||
// reset GS registers to initial dump values
|
||||
std::memcpy(PS2MEM_GS, s_dump_file->GetRegsData().data(),
|
||||
std::min(Ps2MemSize::GSregs, static_cast<u32>(s_dump_file->GetRegsData().size())));
|
||||
|
||||
// load GS state
|
||||
freezeData fd = {static_cast<int>(s_dump_file->GetStateData().size()),
|
||||
const_cast<u8*>(s_dump_file->GetStateData().data())};
|
||||
MTGS_FreezeData mfd = {&fd, 0};
|
||||
GetMTGS().Freeze(FreezeAction::Load, mfd);
|
||||
if (mfd.retval != 0)
|
||||
Host::ReportFormattedErrorAsync("GSDumpReplayer", "Failed to load GS state.");
|
||||
}
|
||||
|
||||
static void GSDumpReplayerSendPacketToMTGS(GIF_PATH path, const u8* data, u32 length)
|
||||
{
|
||||
pxAssert((length % 16) == 0);
|
||||
|
||||
Gif_Path& gifPath = gifUnit.gifPath[path];
|
||||
gifPath.CopyGSPacketData(const_cast<u8*>(data), length);
|
||||
|
||||
GS_Packet gsPack;
|
||||
gsPack.offset = gifPath.curOffset;
|
||||
gsPack.size = length;
|
||||
gifPath.curOffset += length;
|
||||
Gif_AddCompletedGSPacket(gsPack, path);
|
||||
}
|
||||
|
||||
static void GSDumpReplayerUpdateFrameLimit()
|
||||
{
|
||||
constexpr u32 default_frame_limit = 60;
|
||||
const u32 frame_limit = static_cast<u32>(default_frame_limit * EmuConfig.GS.LimitScalar);
|
||||
|
||||
if (frame_limit > 0)
|
||||
s_frame_ticks = (GetTickFrequency() + (frame_limit / 2)) / frame_limit;
|
||||
else
|
||||
s_frame_ticks = 0;
|
||||
}
|
||||
|
||||
static void GSDumpReplayerFrameLimit()
|
||||
{
|
||||
if (s_frame_ticks == 0)
|
||||
return;
|
||||
|
||||
// Frame limiter
|
||||
u64 now = GetCPUTicks();
|
||||
const s64 ms = GetTickFrequency() / 1000;
|
||||
const s64 sleep = s_next_frame_time - now - ms;
|
||||
if (sleep > ms)
|
||||
Threading::Sleep(sleep / ms);
|
||||
while ((now = GetCPUTicks()) < s_next_frame_time)
|
||||
ShortSpin();
|
||||
s_next_frame_time = std::max(now, s_next_frame_time + s_frame_ticks);
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuStep()
|
||||
{
|
||||
if (s_needs_state_loaded)
|
||||
{
|
||||
GSDumpReplayerLoadInitialState();
|
||||
s_needs_state_loaded = false;
|
||||
}
|
||||
|
||||
const GSDumpFile::GSData& packet = s_dump_file->GetPackets()[s_current_packet];
|
||||
s_current_packet = (s_current_packet + 1) % static_cast<u32>(s_dump_file->GetPackets().size());
|
||||
if (s_current_packet == 0)
|
||||
s_dump_frame_number = 0;
|
||||
|
||||
switch (packet.id)
|
||||
{
|
||||
case GSDumpTypes::GSType::Transfer:
|
||||
{
|
||||
switch (packet.path)
|
||||
{
|
||||
case GSDumpTypes::GSTransferPath::Path1Old:
|
||||
{
|
||||
std::unique_ptr<u8[]> data(new u8[16384]);
|
||||
const s32 addr = 16384 - packet.length;
|
||||
std::memcpy(data.get(), packet.data + addr, packet.length);
|
||||
GSDumpReplayerSendPacketToMTGS(GIF_PATH_1, data.get(), packet.length);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSDumpTypes::GSTransferPath::Path1New:
|
||||
case GSDumpTypes::GSTransferPath::Path2:
|
||||
case GSDumpTypes::GSTransferPath::Path3:
|
||||
{
|
||||
GSDumpReplayerSendPacketToMTGS(static_cast<GIF_PATH>(static_cast<u8>(packet.path) - 1),
|
||||
packet.data, packet.length);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GSDumpTypes::GSType::VSync:
|
||||
{
|
||||
s_dump_frame_number++;
|
||||
GSDumpReplayerCpuCheckExecutionState();
|
||||
GSDumpReplayerUpdateFrameLimit();
|
||||
GSDumpReplayerFrameLimit();
|
||||
GetMTGS().PostVsyncStart(false);
|
||||
VMManager::Internal::VSyncOnCPUThread();
|
||||
}
|
||||
break;
|
||||
|
||||
case GSDumpTypes::GSType::ReadFIFO2:
|
||||
{
|
||||
std::unique_ptr<char[]> arr(new char[*((int*)packet.data)]);
|
||||
GSreadFIFO2((u8*)arr.get(), *((int*)packet.data));
|
||||
}
|
||||
break;
|
||||
|
||||
case GSDumpTypes::GSType::Registers:
|
||||
{
|
||||
std::memcpy(PS2MEM_GS, packet.data, std::min<s32>(packet.length, Ps2MemSize::GSregs));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuExecute()
|
||||
{
|
||||
s_dump_running = true;
|
||||
s_next_frame_time = GetCPUTicks();
|
||||
|
||||
while (s_dump_running)
|
||||
{
|
||||
GSDumpReplayerCpuStep();
|
||||
}
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuCheckExecutionState()
|
||||
{
|
||||
if (VMManager::Internal::IsExecutionInterrupted())
|
||||
s_dump_running = false;
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuThrowException(const BaseException& ex)
|
||||
{
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuThrowCpuException(const BaseR5900Exception& ex)
|
||||
{
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuClear(u32 addr, u32 size)
|
||||
{
|
||||
}
|
||||
|
||||
uint GSDumpReplayerCpuGetCacheReserve()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuSetCacheReserve(uint reserveInMegs)
|
||||
{
|
||||
}
|
||||
|
||||
void GSDumpReplayer::RenderUI()
|
||||
{
|
||||
const float scale = ImGuiManager::GetGlobalScale();
|
||||
const float shadow_offset = std::ceil(1.0f * scale);
|
||||
const float margin = std::ceil(10.0f * scale);
|
||||
const float spacing = std::ceil(5.0f * scale);
|
||||
float position_y = margin;
|
||||
|
||||
ImDrawList* dl = ImGui::GetBackgroundDrawList();
|
||||
ImFont* font = ImGuiManager::GetFixedFont();
|
||||
FastFormatAscii text;
|
||||
ImVec2 text_size;
|
||||
|
||||
#define DRAW_LINE(font, text, color) \
|
||||
do \
|
||||
{ \
|
||||
text_size = font->CalcTextSizeA(font->FontSize, std::numeric_limits<float>::max(), -1.0f, (text), nullptr, nullptr); \
|
||||
dl->AddText(font, font->FontSize, ImVec2(margin + shadow_offset, position_y + shadow_offset), IM_COL32(0, 0, 0, 100), (text)); \
|
||||
dl->AddText(font, font->FontSize, ImVec2(margin, position_y), color, (text)); \
|
||||
position_y += text_size.y + spacing; \
|
||||
} while (0)
|
||||
|
||||
text.Write("Dump Frame: %u", s_dump_frame_number);
|
||||
DRAW_LINE(font, text.c_str(), IM_COL32(255, 255, 255, 255));
|
||||
|
||||
text.Clear();
|
||||
text.Write("Packet Number: %u/%u", s_current_packet, static_cast<u32>(s_dump_file->GetPackets().size()));
|
||||
DRAW_LINE(font, text.c_str(), IM_COL32(255, 255, 255, 255));
|
||||
|
||||
#undef DRAW_LINE
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace GSDumpReplayer
|
||||
{
|
||||
bool IsReplayingDump();
|
||||
|
||||
bool Initialize(const char* filename);
|
||||
void Reset();
|
||||
void Shutdown();
|
||||
|
||||
std::string GetDumpSerial();
|
||||
u32 GetDumpCRC();
|
||||
|
||||
void RenderUI();
|
||||
}
|
||||
+222
-14
@@ -16,8 +16,8 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "GameDatabase.h"
|
||||
#include "Config.h"
|
||||
#include "Host.h"
|
||||
#include "Patch.h"
|
||||
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
@@ -31,6 +31,20 @@
|
||||
#include "fmt/ranges.h"
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
namespace GameDatabaseSchema
|
||||
{
|
||||
static const char* getHWFixName(GSHWFixId id);
|
||||
static std::optional<GSHWFixId> parseHWFixName(const std::string_view& name);
|
||||
static bool isUserHackHWFix(GSHWFixId id);
|
||||
} // namespace GameDatabaseSchema
|
||||
|
||||
namespace GameDatabase
|
||||
{
|
||||
static void parseAndInsert(const std::string_view& serial, const c4::yml::NodeRef& node);
|
||||
static void initDatabase();
|
||||
} // namespace GameDatabase
|
||||
|
||||
static constexpr char GAMEDB_YAML_FILE_NAME[] = "GameIndex.yaml";
|
||||
|
||||
@@ -85,7 +99,7 @@ const char* GameDatabaseSchema::GameEntry::compatAsString() const
|
||||
}
|
||||
}
|
||||
|
||||
void parseAndInsert(const std::string_view& serial, const c4::yml::NodeRef& node)
|
||||
void GameDatabase::parseAndInsert(const std::string_view& serial, const c4::yml::NodeRef& node)
|
||||
{
|
||||
GameDatabaseSchema::GameEntry gameEntry;
|
||||
if (node.has_child("name"))
|
||||
@@ -195,6 +209,25 @@ void parseAndInsert(const std::string_view& serial, const c4::yml::NodeRef& node
|
||||
}
|
||||
}
|
||||
|
||||
if (node.has_child("gsHWFixes"))
|
||||
{
|
||||
for (const ryml::NodeRef& n : node["gsHWFixes"].children())
|
||||
{
|
||||
const std::string_view id_name(n.key().data(), n.key().size());
|
||||
std::optional<GameDatabaseSchema::GSHWFixId> id = GameDatabaseSchema::parseHWFixName(id_name);
|
||||
std::optional<s32> value = n.has_val() ? StringUtil::FromChars<s32>(std::string_view(n.val().data(), n.val().size())) : 1;
|
||||
if (!id.has_value() || !value.has_value())
|
||||
{
|
||||
Console.Error("[GameDB] Invalid GS HW Fix: '%.*s' specified for serial '%.*s'. Dropping!",
|
||||
static_cast<int>(id_name.size()), id_name.data(),
|
||||
static_cast<int>(serial.size()), serial.data());
|
||||
continue;
|
||||
}
|
||||
|
||||
gameEntry.gsHWFixes.emplace_back(id.value(), value.value());
|
||||
}
|
||||
}
|
||||
|
||||
// Memory Card Filters - Store as a vector to allow flexibility in the future
|
||||
// - currently they are used as a '\n' delimited string in the app
|
||||
if (node.has_child("memcardFilters") && node["memcardFilters"].has_children())
|
||||
@@ -231,16 +264,194 @@ void parseAndInsert(const std::string_view& serial, const c4::yml::NodeRef& node
|
||||
s_game_db.emplace(std::move(serial), std::move(gameEntry));
|
||||
}
|
||||
|
||||
static std::ifstream getFileStream(std::string path)
|
||||
static const char* s_gs_hw_fix_names[] = {
|
||||
"autoFlush",
|
||||
"conservativeFramebuffer",
|
||||
"cpuFramebufferConversion",
|
||||
"disableDepthSupport",
|
||||
"wrapGSMem",
|
||||
"preloadFrameData",
|
||||
"disablePartialInvalidation",
|
||||
"textureInsideRT",
|
||||
"alignSprite",
|
||||
"mergeSprite",
|
||||
"wildArmsHack",
|
||||
"pointListPalette",
|
||||
"mipmap",
|
||||
"trilinearFiltering",
|
||||
"skipDrawStart",
|
||||
"skipDrawEnd",
|
||||
"halfBottomOverride",
|
||||
"halfPixelOffset",
|
||||
"roundSprite",
|
||||
"texturePreloading",
|
||||
};
|
||||
static_assert(std::size(s_gs_hw_fix_names) == static_cast<u32>(GameDatabaseSchema::GSHWFixId::Count), "HW fix name lookup is correct size");
|
||||
|
||||
const char* GameDatabaseSchema::getHWFixName(GSHWFixId id)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return std::ifstream(StringUtil::UTF8StringToWideString(path));
|
||||
#else
|
||||
return std::ifstream(path.c_str());
|
||||
#endif
|
||||
return s_gs_hw_fix_names[static_cast<u32>(id)];
|
||||
}
|
||||
|
||||
static void initDatabase()
|
||||
static std::optional<GameDatabaseSchema::GSHWFixId> GameDatabaseSchema::parseHWFixName(const std::string_view& name)
|
||||
{
|
||||
for (u32 i = 0; i < std::size(s_gs_hw_fix_names); i++)
|
||||
{
|
||||
if (name.compare(s_gs_hw_fix_names[i]) == 0)
|
||||
return static_cast<GameDatabaseSchema::GSHWFixId>(i);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool GameDatabaseSchema::isUserHackHWFix(GSHWFixId id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case GSHWFixId::Mipmap:
|
||||
case GSHWFixId::TexturePreloading:
|
||||
case GSHWFixId::ConservativeFramebuffer:
|
||||
case GSHWFixId::PointListPalette:
|
||||
return false;
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
// Trifiltering isn't a hack in Qt.
|
||||
case GSHWFixId::TrilinearFiltering:
|
||||
return false;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions& config) const
|
||||
{
|
||||
// Only apply GS HW fixes if the user hasn't manually enabled HW fixes.
|
||||
const bool apply_auto_fixes = !config.ManualUserHacks;
|
||||
if (!apply_auto_fixes)
|
||||
Console.Warning("[GameDB] Manual GS hardware renderer fixes are enabled, not using automatic hardware renderer fixes from GameDB.");
|
||||
|
||||
u32 num_applied_fixes = 0;
|
||||
for (const auto& [id, value] : gsHWFixes)
|
||||
{
|
||||
if (isUserHackHWFix(id) && !apply_auto_fixes)
|
||||
{
|
||||
PatchesCon->Warning("[GameDB] Skipping GS Hardware Fix: %s to [mode=%d]", getHWFixName(id), value);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case GSHWFixId::AutoFlush:
|
||||
config.UserHacks_AutoFlush = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::ConservativeFramebuffer:
|
||||
config.ConservativeFramebuffer = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::CPUFramebufferConversion:
|
||||
config.UserHacks_CPUFBConversion = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::DisableDepthSupport:
|
||||
config.UserHacks_DisableDepthSupport = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::WrapGSMem:
|
||||
config.WrapGSMem = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::PreloadFrameData:
|
||||
config.PreloadFrameWithGSData = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::DisablePartialInvalidation:
|
||||
config.UserHacks_DisablePartialInvalidation = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::TextureInsideRT:
|
||||
config.UserHacks_TextureInsideRt = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::AlignSprite:
|
||||
config.UserHacks_AlignSpriteX = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::MergeSprite:
|
||||
config.UserHacks_MergePPSprite = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::WildArmsHack:
|
||||
config.UserHacks_WildHack = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::PointListPalette:
|
||||
config.PointListPalette = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::Mipmap:
|
||||
{
|
||||
if (value >= 0 && value <= static_cast<int>(HWMipmapLevel::Full))
|
||||
{
|
||||
if (config.HWMipmap == HWMipmapLevel::Automatic)
|
||||
config.HWMipmap = static_cast<HWMipmapLevel>(value);
|
||||
else if (config.HWMipmap == HWMipmapLevel::Off)
|
||||
Console.Warning("[GameDB] Game requires mipmapping but it has been force disabled.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GSHWFixId::TrilinearFiltering:
|
||||
{
|
||||
if (value >= 0 && value <= static_cast<int>(TriFiltering::Forced))
|
||||
config.UserHacks_TriFilter = static_cast<TriFiltering>(value);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSHWFixId::SkipDrawStart:
|
||||
config.SkipDrawStart = value;
|
||||
break;
|
||||
|
||||
case GSHWFixId::SkipDrawEnd:
|
||||
config.SkipDrawEnd = value;
|
||||
break;
|
||||
|
||||
case GSHWFixId::HalfBottomOverride:
|
||||
config.UserHacks_HalfBottomOverride = value;
|
||||
break;
|
||||
|
||||
case GSHWFixId::HalfPixelOffset:
|
||||
config.UserHacks_HalfPixelOffset = value;
|
||||
break;
|
||||
|
||||
case GSHWFixId::RoundSprite:
|
||||
config.UserHacks_RoundSprite = value;
|
||||
break;
|
||||
|
||||
case GSHWFixId::TexturePreloading:
|
||||
{
|
||||
if (value >= 0 && value <= static_cast<int>(TexturePreloadingLevel::Full))
|
||||
config.TexturePreloading = std::min(config.TexturePreloading, static_cast<TexturePreloadingLevel>(value));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
PatchesCon->WriteLn("[GameDB] Enabled GS Hardware Fix: %s to [mode=%d]", getHWFixName(id), value);
|
||||
num_applied_fixes++;
|
||||
}
|
||||
|
||||
// fixup skipdraw range just in case the db has a bad range (but the linter should catch this)
|
||||
config.SkipDrawEnd = std::max(config.SkipDrawStart, config.SkipDrawEnd);
|
||||
|
||||
return num_applied_fixes;
|
||||
}
|
||||
|
||||
void GameDatabase::initDatabase()
|
||||
{
|
||||
ryml::Callbacks rymlCallbacks = ryml::get_callbacks();
|
||||
rymlCallbacks.m_error = [](const char* msg, size_t msg_len, ryml::Location loc, void*) {
|
||||
@@ -254,15 +465,14 @@ static void initDatabase()
|
||||
});
|
||||
try
|
||||
{
|
||||
std::optional<std::vector<u8>> buf(Host::ReadResourceFile(GAMEDB_YAML_FILE_NAME));
|
||||
auto buf = Host::ReadResourceFileToString(GAMEDB_YAML_FILE_NAME);
|
||||
if (!buf.has_value())
|
||||
{
|
||||
Console.Error("[GameDB] Unable to open GameDB file, file does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
const ryml::substr view = c4::basic_substring<char>(reinterpret_cast<char*>(buf->data()), buf->size());
|
||||
ryml::Tree tree = ryml::parse(view);
|
||||
ryml::Tree tree = ryml::parse_in_arena(c4::to_csubstr(buf.value()));
|
||||
ryml::NodeRef root = tree.rootref();
|
||||
|
||||
for (const ryml::NodeRef& n : root.children())
|
||||
@@ -291,8 +501,6 @@ static void initDatabase()
|
||||
ryml::reset_callbacks();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GameDatabase::ensureLoaded()
|
||||
{
|
||||
std::call_once(s_load_once_flag, []() {
|
||||
|
||||
+38
-3
@@ -15,16 +15,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
enum GamefixId;
|
||||
enum SpeedhackId;
|
||||
|
||||
class GameDatabaseSchema
|
||||
namespace GameDatabaseSchema
|
||||
{
|
||||
public:
|
||||
enum class Compatibility
|
||||
{
|
||||
Unknown = 0,
|
||||
@@ -54,6 +56,35 @@ public:
|
||||
Full
|
||||
};
|
||||
|
||||
enum class GSHWFixId : u32
|
||||
{
|
||||
// boolean settings
|
||||
AutoFlush,
|
||||
ConservativeFramebuffer,
|
||||
CPUFramebufferConversion,
|
||||
DisableDepthSupport,
|
||||
WrapGSMem,
|
||||
PreloadFrameData,
|
||||
DisablePartialInvalidation,
|
||||
TextureInsideRT,
|
||||
AlignSprite,
|
||||
MergeSprite,
|
||||
WildArmsHack,
|
||||
PointListPalette,
|
||||
|
||||
// integer settings
|
||||
Mipmap,
|
||||
TrilinearFiltering,
|
||||
SkipDrawStart,
|
||||
SkipDrawEnd,
|
||||
HalfBottomOverride,
|
||||
HalfPixelOffset,
|
||||
RoundSprite,
|
||||
TexturePreloading,
|
||||
|
||||
Count
|
||||
};
|
||||
|
||||
using Patch = std::vector<std::string>;
|
||||
|
||||
struct GameEntry
|
||||
@@ -67,6 +98,7 @@ public:
|
||||
ClampMode vuClampMode = ClampMode::Undefined;
|
||||
std::vector<GamefixId> gameFixes;
|
||||
std::vector<std::pair<SpeedhackId, int>> speedHacks;
|
||||
std::vector<std::pair<GSHWFixId, s32>> gsHWFixes;
|
||||
std::vector<std::string> memcardFilters;
|
||||
std::unordered_map<std::string, Patch> patches;
|
||||
|
||||
@@ -74,6 +106,9 @@ public:
|
||||
std::string memcardFiltersAsString() const;
|
||||
const Patch* findPatch(const std::string_view& crc) const;
|
||||
const char* compatAsString() const;
|
||||
|
||||
/// Applies GS hardware fixes to an existing config. Returns the number of applied fixes.
|
||||
u32 applyGSHardwareFixes(Pcsx2Config::GSOptions& config) const;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
+23
-7
@@ -60,16 +60,16 @@ struct Gif_Tag
|
||||
bool hasAD; // Has an A+D Write
|
||||
bool isValid; // Tag is valid
|
||||
|
||||
Gif_Tag() { Reset(); }
|
||||
Gif_Tag(u8* pMem, bool analyze = false)
|
||||
__ri Gif_Tag() { Reset(); }
|
||||
__ri Gif_Tag(u8* pMem, bool analyze = false)
|
||||
{
|
||||
setTag(pMem, analyze);
|
||||
}
|
||||
|
||||
void Reset() { memzero(*this); }
|
||||
u8 curReg() { return regs[nRegIdx & 0xf]; }
|
||||
__ri void Reset() { memzero(*this); }
|
||||
__ri u8 curReg() { return regs[nRegIdx & 0xf]; }
|
||||
|
||||
void packedStep()
|
||||
__ri void packedStep()
|
||||
{
|
||||
if (nLoop > 0)
|
||||
{
|
||||
@@ -82,7 +82,7 @@ struct Gif_Tag
|
||||
}
|
||||
}
|
||||
|
||||
void setTag(u8* pMem, bool analyze = false)
|
||||
__ri void setTag(u8* pMem, bool analyze = false)
|
||||
{
|
||||
tag = *(HW_Gif_Tag*)pMem;
|
||||
nLoop = tag.NLOOP;
|
||||
@@ -115,8 +115,23 @@ struct Gif_Tag
|
||||
}
|
||||
}
|
||||
|
||||
void analyzeTag()
|
||||
__ri void analyzeTag()
|
||||
{
|
||||
#ifdef _M_X86
|
||||
// zero out bits for registers which shouldn't be tested
|
||||
__m128i vregs = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(tag.REGS));
|
||||
vregs = _mm_and_si128(vregs, _mm_srli_epi64(_mm_set1_epi32(0xFFFFFFFFu), (64 - nRegs * 4)));
|
||||
|
||||
// get upper nibbles, interleave with lower nibbles, clear upper bits from low nibbles
|
||||
vregs = _mm_and_si128(_mm_unpacklo_epi8(vregs, _mm_srli_epi32(vregs, 4)), _mm_set1_epi8(0x0F));
|
||||
|
||||
// compare with GIF_REG_A_D, set hasAD if any lanes passed
|
||||
hasAD = (_mm_movemask_epi8(_mm_cmpeq_epi8(vregs, _mm_set1_epi8(GIF_REG_A_D))) != 0);
|
||||
|
||||
// write out unpacked registers
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(regs), vregs);
|
||||
#else
|
||||
// Reference C implementation.
|
||||
hasAD = false;
|
||||
u32 t = tag.REGS[0];
|
||||
u32 i = 0;
|
||||
@@ -135,6 +150,7 @@ struct Gif_Tag
|
||||
hasAD |= (regs[i] == GIF_REG_A_D);
|
||||
t >>= 4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -53,6 +53,15 @@ bool HostDisplay::GetHostRefreshRate(float* refresh_rate)
|
||||
return WindowInfo::QueryRefreshRateForWindow(m_window_info, refresh_rate);
|
||||
}
|
||||
|
||||
void HostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
float HostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
bool HostDisplay::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate)
|
||||
{
|
||||
if (!mode.empty())
|
||||
|
||||
@@ -133,6 +133,12 @@ public:
|
||||
/// Returns the effective refresh rate of this display.
|
||||
virtual bool GetHostRefreshRate(float* refresh_rate);
|
||||
|
||||
/// Enables/disables GPU frame timing.
|
||||
virtual void SetGPUTimingEnabled(bool enabled);
|
||||
|
||||
/// Returns the amount of GPU time utilized since the last time this method was called.
|
||||
virtual float GetAndResetAccumulatedGPUTime();
|
||||
|
||||
/// Returns true if it's an OpenGL-based renderer.
|
||||
bool UsesLowerLeftOrigin() const;
|
||||
|
||||
|
||||
-17
@@ -363,23 +363,6 @@ enum GSRegisterAddresses
|
||||
GS_SIGLBLID = 0x12001080
|
||||
};
|
||||
|
||||
// bleh, I'm graindead -- air
|
||||
union tGS_SMODE2
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 INT:1;
|
||||
u32 FFMD:1;
|
||||
u32 DPMS:2;
|
||||
u32 _PAD2:28;
|
||||
u32 _PAD3:32;
|
||||
};
|
||||
|
||||
u64 _u64;
|
||||
|
||||
bool IsInterlaced() const { return INT; }
|
||||
};
|
||||
|
||||
extern void hwReset();
|
||||
extern void hwShutdown();
|
||||
|
||||
|
||||
+6
-5
@@ -146,7 +146,7 @@ void VU_Thread::ExecuteRingBuffer()
|
||||
s32 addr = Read();
|
||||
vifRegs.top = Read();
|
||||
vifRegs.itop = Read();
|
||||
|
||||
vuFBRST = Read();
|
||||
if (addr != -1)
|
||||
vuRegs.VI[REG_TPC].UL = addr & 0x7FF;
|
||||
vuCPU->SetStartPC(vuRegs.VI[REG_TPC].UL << 3);
|
||||
@@ -406,13 +406,13 @@ void VU_Thread::Get_MTVUChanges()
|
||||
{
|
||||
mtvuInterrupts.fetch_and(~InterruptFlagVUEBit, std::memory_order_relaxed);
|
||||
|
||||
VU0.VI[REG_VPU_STAT].UL &= ~0x0100;
|
||||
VU0.VI[REG_VPU_STAT].UL &= ~0xFF00;
|
||||
//DevCon.Warning("E-Bit registered %x", VU0.VI[REG_VPU_STAT].UL);
|
||||
}
|
||||
if (interrupts & InterruptFlagVUTBit)
|
||||
{
|
||||
mtvuInterrupts.fetch_and(~InterruptFlagVUTBit, std::memory_order_relaxed);
|
||||
VU0.VI[REG_VPU_STAT].UL &= ~0x0100;
|
||||
VU0.VI[REG_VPU_STAT].UL &= ~0xFF00;
|
||||
VU0.VI[REG_VPU_STAT].UL |= 0x0400;
|
||||
//DevCon.Warning("T-Bit registered %x", VU0.VI[REG_VPU_STAT].UL);
|
||||
hwIntcIrq(7);
|
||||
@@ -445,15 +445,16 @@ void VU_Thread::WaitVU()
|
||||
}
|
||||
}
|
||||
|
||||
void VU_Thread::ExecuteVU(u32 vu_addr, u32 vif_top, u32 vif_itop)
|
||||
void VU_Thread::ExecuteVU(u32 vu_addr, u32 vif_top, u32 vif_itop, u32 fbrst)
|
||||
{
|
||||
MTVU_LOG("MTVU - ExecuteVU!");
|
||||
Get_MTVUChanges(); // Clear any pending interrupts
|
||||
ReserveSpace(4);
|
||||
ReserveSpace(5);
|
||||
Write(MTVU_VU_EXECUTE);
|
||||
Write(vu_addr);
|
||||
Write(vif_top);
|
||||
Write(vif_itop);
|
||||
Write(fbrst);
|
||||
CommitWritePos();
|
||||
gifUnit.TransferGSPacketData(GIF_TRANS_MTVU, NULL, 0);
|
||||
KickStart();
|
||||
|
||||
+2
-1
@@ -47,6 +47,7 @@ public:
|
||||
Semaphore semaXGkick;
|
||||
std::atomic<unsigned int> vuCycles[4]; // Used for VU cycle stealing hack
|
||||
u32 vuCycleIdx; // Used for VU cycle stealing hack
|
||||
u32 vuFBRST;
|
||||
|
||||
enum InterruptFlag {
|
||||
InterruptFlagFinish = 1 << 0,
|
||||
@@ -76,7 +77,7 @@ public:
|
||||
|
||||
void Get_MTVUChanges();
|
||||
|
||||
void ExecuteVU(u32 vu_addr, u32 vif_top, u32 vif_itop);
|
||||
void ExecuteVU(u32 vu_addr, u32 vif_top, u32 vif_itop, u32 fbrst);
|
||||
|
||||
void VifUnpack(vifStruct& _vif, VIFregisters& _vifRegs, u8* data, u32 size);
|
||||
|
||||
|
||||
+11
-1
@@ -49,6 +49,10 @@ BIOS
|
||||
|
||||
#include "common/PageFaultSource.h"
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
#include "GSDumpReplayer.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLECACHE
|
||||
#include "Cache.h"
|
||||
#endif
|
||||
@@ -850,7 +854,13 @@ void eeMemoryReserve::Reset()
|
||||
vtlb_VMap(0x00000000,0x00000000,0x20000000);
|
||||
vtlb_VMapUnmap(0x20000000,0x60000000);
|
||||
|
||||
if (!LoadBIOS())
|
||||
#ifdef PCSX2_CORE
|
||||
const bool needs_bios = !GSDumpReplayer::IsReplayingDump();
|
||||
#else
|
||||
constexpr bool needs_bios = true;
|
||||
#endif
|
||||
|
||||
if (needs_bios && !LoadBIOS())
|
||||
pxFailRel("Failed to load BIOS");
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user