Compare commits

..
112 Commits
Author SHA1 Message Date
Mrlinkwii 224863fbd5 GameDB: adds 'VUSyncHack' to Panzer Elite Action - Fields of Glory 2022-03-20 17:40:43 +00:00
Mrlinkwii 1d459d8fab Gamedb: Remove VU rounding form 'Hitman - Contracts' 2022-03-20 15:30:00 +00:00
arcum42@gmail.com 33e0ac729e Core: Remove memcmp_mmx. 2022-03-20 12:54:58 +00:00
Connor McLaughlin 268ecf42c3 Build: Remove 32bit configs from vsprops 2022-03-20 12:53:42 +00:00
refractionpcsx2 708281f00b GS: Properly detect 16bit format on Texture Shuffle + Convert 2022-03-20 06:49:16 +00:00
RedDevilus 56b68a50e9 GameDB: Even more GS HW Fixes
Affects:
Ape Escape 3
Armored Core Last Raven
Berserk
Forever Kingdom
Front Mission 4 / 5
Need For Speed Underground 1 / 2
Kings Field 4 - The Ancient City
Test Drive Unlimited
Jak 2 / 3 / X
2022-03-20 05:57:18 +00:00
RedDevilus e4048dc2dd CI: Update labeler to expand WX 2022-03-20 04:50:29 +00:00
TheLastRar 5949c772d1 Qt: Fix bugs relating to per-game settings 2022-03-20 04:13:45 +00:00
RafaelTrepaUnCarballo 63998b64cc fix comment format 2022-03-20 04:10:11 +00:00
RafaelTrepaUnCarballo fbb3ea142a Add files via upload
Added gshack (wild arms hack) for all releases of Wild Arms Alter Code F
2022-03-20 04:10:11 +00:00
Tyler Wilding 435f760b5d GameDB: remove duplicate YAML keys 2022-03-20 04:03:03 +00:00
Tyler Wilding f47129bd72 deps: update rapid-yaml to v0.4.1 2022-03-20 04:03:03 +00:00
Tyler Wilding aa42acfe22 common: fix method name and clarify some behaviour 2022-03-20 04:03:03 +00:00
Tyler Wilding ddfe6ac5c1 memcard: update ryml parsing for folder memory cards
also make the file handling safer
2022-03-20 04:03:03 +00:00
Tyler Wilding 624dff1b96 gamedb: move away from deprecated ryml::parse func 2022-03-20 04:03:03 +00:00
Tyler Wilding 8d498b564d deps: update rapid-yaml to latest commit
has a bug fix that we hit in folder memory cards
2022-03-20 04:03:03 +00:00
Christian Kenny 26561261bc Core: Remove unused code 2022-03-20 04:00:27 +00:00
Connor McLaughlin 44728be719 Misc: Fix incorrect printf of std::string_view 2022-03-20 04:00:13 +00:00
Tzerinas 678bb1218b GameDB: Add fixes for Tak Games
SoftwareRendererFMVHack for Tak 1&2, Half-Pixel Offset (Texture) for Guardians of Gross.
2022-03-20 04:00:04 +00:00
RedDevilus c496e80eac PCSX2-GUI: Rename skipdraw and IDC for Partial Invalidation
Skipdraw and SkipDrawOffset isn't obvious to what it is. SkipDrawStart and SkipDrawEnd makes it obvious it's a range of values.
Also forgot to change the IDC for Disabling Partial Invalidation.
2022-03-20 03:59:38 +00:00
refractionpcsx2 269db188d0 Build: Remove 32bit from CMake. 2022-03-20 00:39:39 +00:00
refractionpcsx2 f5afbfd4f5 GS: Remove 32bit code from SW renderer 2022-03-20 00:39:39 +00:00
refractionpcsx2 ccd86a242c EE/VU JIT: Remove 32bit code 2022-03-20 00:39:39 +00:00
refractionpcsx2 42a5cb7ad2 Build: Remove 32bit targets from VS solution 2022-03-20 00:39:39 +00:00
Tyler Wilding 6977323d88 ci: remove redundant words from job names
its always 64bit now!
2022-03-19 21:19:48 +00:00
Tyler Wilding 7b1d03d45a ci: add link to previous release page in discord announcement 2022-03-19 21:19:48 +00:00
Tyler Wilding 8a4f1ef51a ci: stop building 32-bit
At this point -- not cleaning up the solution files / etc, only our actions.

Until the 32bit code itself is removed, we should still have an easy way to flip these back on.
2022-03-19 21:19:48 +00:00
Mrlinkwii 9b50bb2e81 Gamedb: remove no longer needed comments 2022-03-19 15:56:06 +00:00
Connor McLaughlin 4f27d779a1 GS/DX11: Fix incorrect format check for compressed textures 2022-03-19 03:57:20 +00:00
RedDevilus 73c6353351 Qt: Partial Invalidation
Some missing strings from the renaming.
2022-03-18 23:47:21 +00:00
Immersion95 f571b66a43 GameDB: HW fixes for Mega Man/Rockman X7 + Clamping mode fix (#5694) 2022-03-18 20:53:48 +00:00
BuildTools 901664ba44 GameDB: Rename fastTextureInvalidation
Attempt 2 renames fastTextureInvalidation to disablePartialInvalidation for more consistency with the new GUI name.
2022-03-18 13:52:36 +00:00
Immersion95 02012b5491 GameDB: HW fixes for Rockman X8
SoftwareRendererFMVHack for the NTSC-J & NTSC-K version of Megaman X8
2022-03-18 10:24:58 +00:00
TellowKrinkle 4f57e40c91 GS:SW: Fix lod on x64 2022-03-18 03:59:51 -05:00
RedDevilus 832e536a9e GameDB: Haunting Ground + 50 Cent and Level 5
Ranging from blurriness to font artifacts.
2022-03-18 08:44:33 +00:00
BuildTools c2316ca5bc GUI: Rename Fast Texture Invalidation
Renames Fast Texture Invalidation to Disable Partial Invalidation.

Update GraphicsSettingsWidget.ui
2022-03-18 02:11:12 +00:00
refractionpcsx2 3535edcfa1 GameDB: Add partial preloading to Stolen 2022-03-17 18:40:11 +00:00
KrossX a4932ed0f1 GameDB: Add DMABusy fix to Shining Wind 2022-03-17 14:33:07 +00:00
seta-sanandRedDevilus 515d9040a1 GameDB: Add gsHWFixes for Tales of Symphonia
Co-Authored-By: RedDevilus <martensregis@gmail.com>
2022-03-17 09:16:20 +00:00
Connor McLaughlin fe3a743814 ImGuiManager: Cap usage percents to 100% 2022-03-17 09:10:12 +00:00
Connor McLaughlin 8e08cd772b PerformanceMetrics: Add GPU time 2022-03-17 09:10:12 +00:00
Connor McLaughlin 206f80c5f4 GS: Compute SW CPU per-thread not per-draw 2022-03-17 09:10:12 +00:00
RedDevilus c6ce380042 GameDB: More GS HW Fixes
Some extra comments for Monster Lab and SSX Tricky.

New entries:

- Alter Echo
- Beyond Good and Evil
- Dragon Ball Z - Budokai Tenkaichi 2
- Fatal Frame 1 / 3
- Ghost in the Shell - Stand Alone Complex
- Global Defence Force
- Xenosaga 1 / 2 / 3
2022-03-17 08:57:58 +00:00
lightningterror 939d98d660 Qt: Allow skipdraw up to 10k max. 2022-03-17 02:44:14 +01:00
lightningterror c9a3420f85 GS: Fix Wunused-variable warnings. 2022-03-17 00:50:28 +01:00
refractionpcsx2 9a1a399bac GameDB: Add a bunch of hw fixes and upscaling fixes 2022-03-16 23:40:53 +00:00
RedDevilus c8aac1dca9 GameDB: Ace Combat + Soul Calibur + Metal Gear Solid Series
Missing mipmap from the Europese Ace Combat Zero/4/5, Align Sprite for them and Round Sprite. Align Sprite for SoulCalibur series.
Metal Gear 2 substance gets round sprite for font and Metal Gear 3 Subsistence gets Special (Texture) for blurriness.
2022-03-16 22:38:39 +00:00
lightningterror 14c17916f5 GS-hw: Optimize blending equations based on alpha value.
It will allow us to use free sw blending without texture barriers.

Will be especially helpful for opengl/vulkan.
2022-03-16 15:17:00 +01:00
RedDevilus 7b0576d7cc GameDB: Dog Island and COD Final Fronts (#5671) 2022-03-16 07:24:05 +00:00
Blackbird88 ecb118d5af GameDB: Add gsHWFixes for GTA LCS/VCS (#5662)
Co authored by @Blackbird88
2022-03-15 20:22:19 +00:00
RedDevilus efbf187b35 GameDB: Upscaling GS Batch 2
Adds second batch of upscaling fixes.
2022-03-15 20:21:15 +00:00
Tzerinas 2ea3feba90 GameDB: Add Upscaling Fixes to Onimusha 3
Adds Half-Pixel Offset: Special (Texture) and Round Sprite (Full) to Onimusha 3: Demon Siege
2022-03-15 20:19:06 +00:00
Tzerinas f265257efb GameDB: Add Software FMV to Grandia 2 and Xtreme
Adds the SoftwareRendererFMV hack to Grandia 2 and Xtreme. Also adjusted titles.
2022-03-15 20:18:43 +00:00
lightningterror 13cc0caed7 GS Debugger: Fix hw hacks behavior not properly disabling. 2022-03-15 15:46:24 +01:00
refractionpcsx2 2068240e1a GS: Adjust Auto Flush to catch edge cases
Affected Beyond Good and Evil water
2022-03-15 10:15:21 +00:00
Tzerinas 7f5901f022 GameDB: GS HW renderer fixes for Tales of the Abyss
Description of Changes
Add Half-Pixel Offset: Special (Texture) to Tales of the Abyss.
2022-03-15 09:38:24 +00:00
Tokman5andTokman5 a022de6225 GameDB: Add gsHWFixes for Shutokou Battle 01. (#5659)
Co-authored-by: Tokman5 <isozin_1210@yahoo.co.jp>
2022-03-15 08:12:52 +00:00
RedDevilus f5570b7f40 GameDB: Rogue Galaxy
Adds half roundsprite to make upscaled HW more like software mode such as minimap while fighting.
2022-03-15 08:11:17 +00:00
RedDevilus 7e1c48694a GameDB: Upscaling GS Batch 1
Fixes the lint and adds a bunch of upscaling fixes.
2022-03-15 00:54:38 +00:00
lightningterror a546f61ea8 Qt: Fix Round sprite hack not applying. 2022-03-14 23:43:25 +01:00
PCSX2 Bot 7ecac10eee PAD: Update to latest controller database. 2022-03-14 22:20:49 +01:00
Mrlinkwii ee2e10e86b GameDB: correct and update serials 2022-03-14 19:15:50 +00:00
RedDevilus 7752f44a90 GameDB: Documentation
Add values for GameDB, GUI options and the default to easier make GameDB changes
2022-03-14 19:14:40 +00:00
refractionpcsx2 e01fc3eb47 GS: Loosen requirement for half bottom 2022-03-14 19:14:26 +00:00
SaltyBet 910c8190e0 GameDB: Added missing variants of NAMCO games 2022-03-14 15:47:02 +00:00
SaltyBet a62ccc0d69 GameDB: Auto GS HW renderer fixes for some NAMCO games
- Tekken 4
- Tekken 5
- Tekken Tag Tournament
2022-03-14 15:47:02 +00:00
Dreadmoth 4f47041108 GameDB: Metal Arms - Glitch in the System (PAL)
Force disable mVU Flag Hack to prevent SPS
2022-03-14 15:33:39 +00:00
Connor McLaughlin 16cfde0538 GS: Use single array for dump packets 2022-03-14 15:26:19 +00:00
Connor McLaughlin 6a15d46461 Qt: Improve boot filename autodetection 2022-03-14 15:26:19 +00:00
Connor McLaughlin 4331ae1925 VMManager: Support playing back GS dumps 2022-03-14 15:26:19 +00:00
Connor McLaughlin 4d85d916b7 GS: Move dump file loading to core 2022-03-14 15:26:19 +00:00
Connor McLaughlin 4f4b14dd4d GameList: Add GetEntryByCRC() 2022-03-14 15:26:19 +00:00
Connor McLaughlin 444e650711 StringUtil: Add StartsWithNoCase/EndsWithNoCase 2022-03-14 15:26:19 +00:00
refractionpcsx2 c65ccaa153 GS-Config: Clear missing manual GS fixes 2022-03-14 11:08:39 +00:00
Connor McLaughlin 6b54db9b75 GS/VertexTrace: Fix min/max when last provoking vertex unsupported
This was causing incorrect min/max alpha values due to the index swap,
which caused the sides of text boxes in KH to disappear (because the
alpha test optimized to always failing).

Closes #5639.
2022-03-14 08:47:32 +00:00
Mrlinkwii 3bab470db6 Docs : Add GS hardware fixes and MTVUSpeedHack 2022-03-13 18:33:37 +00:00
refractionpcsx2 adf01cb56a GS-Build: Fix Dump Verticles for linux 2022-03-13 05:01:51 +00:00
refractionpcsx2 bbe3af7f61 GS-Debug: Dump verticles with draws
- Move context dumping to the top so we see it as the game set, not after we've messed with it.
Thanks to tadanokojin for these changes
2022-03-13 03:46:16 +00:00
refractionpcsx2 3e7d32c807 GameDB: Give slightly clearer message for GS Fix override 2022-03-13 03:18:44 +00:00
refractionpcsx2 76e25cb738 GameDB: Add mipmapping/trilinear for Hot Shots/Everybody's Golf games 2022-03-13 02:34:29 +00:00
refractionpcsx2 8f0dc34847 GS: Improvements to MTBA address calculation 2022-03-13 01:55:08 +00:00
RedDevilus fc6ec2cc02 GameDB: Transformers Armada: Prelude to Energon
Adds missing VIFFIFO + force disabling MTVU for not getting black screen
2022-03-13 01:53:48 +00:00
refractionpcsx2 34b7b07ff8 GameDB: Added a whole host of auto GS HW renderer fixes 2022-03-13 01:53:15 +00:00
Connor McLaughlin 6c33b73cdd GS: Make TC offset changable without recreating 2022-03-12 20:48:51 +00:00
Connor McLaughlin 1e86ba4120 GS: Append game serial/name to dump filename 2022-03-12 20:48:51 +00:00
Connor McLaughlin 89c79aa6c3 GSDump: Add embedded screenshot 2022-03-12 20:48:51 +00:00
Connor McLaughlin 4ed748fa30 GSDump: Add extensible header and serial
Serial is used to apply hw fixes.
2022-03-12 20:48:51 +00:00
Connor McLaughlin 5569e94f41 GS: Make setting change detection more fine grained
Avoids the slower full restart when it's not needed.
2022-03-12 20:48:51 +00:00
Connor McLaughlin 892eec79ed Workflows: Fix lint-gamedb for gsHWFixes 2022-03-12 20:48:51 +00:00
Connor McLaughlin b248b4a8af GameDB: Add HW fixes for GTASA/GOW/GOW2 2022-03-12 20:48:51 +00:00
Connor McLaughlin 39fe467b64 GS: Purge CRCs of unused titles 2022-03-12 20:48:51 +00:00
Connor McLaughlin 1c301ec889 GS: Move point list palette to gamedb 2022-03-12 20:48:51 +00:00
Connor McLaughlin de5690ddcb GS: Move texture-inside-rt flag to gamedb 2022-03-12 20:48:51 +00:00
Connor McLaughlin f376c8f7ae GS: Remove second source of truth for HWMipmap 2022-03-12 20:48:51 +00:00
Connor McLaughlin 2e199d47a8 GS: Move automatic mipmapping override to gamedb 2022-03-12 20:48:51 +00:00
Connor McLaughlin 96269db93e GameDatabase: Add ability to override GS fixes 2022-03-12 20:48:51 +00:00
Connor McLaughlin d35db63d73 GS: Reference GSConfig instead of using theApp
Removes multiple sources of truth, enables overrides.
2022-03-12 20:48:51 +00:00
refractionpcsx2 9d003486c2 GS-hw: Attempt to improve half screen detection 2022-03-12 12:28:18 +00:00
refractionpcsx2 0c4b85980c GS: Support local to local transfers that overwrite themselves 2022-03-12 12:27:43 +00:00
Connor McLaughlin 5961db6b9b GS/Vulkan: Elide render pass restarts on depth buffer toggle 2022-03-12 12:22:51 +00:00
Connor McLaughlin d0039c2920 Gif_Unit: Vectorize analyzeTag() 2022-03-12 12:10:32 +00:00
TellowKrinkle 5bdec2f532 x86emitter: Fix x64 8-bit rmw codegen 2022-03-11 12:59:57 +00:00
refractionpcsx2 fd758bb307 GameDB: Added MTVU disable to InstantVU off games 2022-03-11 10:25:15 +00:00
refractionpcsx2 a11d09ebdf Git: Update GameDB Validation script 2022-03-11 10:25:15 +00:00
refractionpcsx2 d294064da6 GameDB: Disable MTVU on T-Bit games 2022-03-11 10:25:15 +00:00
refractionpcsx2 fd4a5acc40 MTVU: Try to make T-Bit more reliable.
Add MTVUSpeedHack option to GameDB so it can be forcefully disabled
2022-03-11 10:25:15 +00:00
refractionpcsx2 05a7a61257 GS/Autoflush: Handle different page widths/arrangements 2022-03-11 10:24:26 +00:00
refractionpcsx2 90a4a11d49 GS: Add Auto Flush for Z buffer draws
Adjust Burnout CRC hack
2022-03-11 10:24:26 +00:00
lightningterror d9f914eb7c GS-hw: Move the Ad to As equation swap when alpha is masked to Basic level and higher on gl/vk.
Safer this way, otherwise need to take in to account when accumulation, non recursive, and blend mix is enabled, or manually enable them on Minimum level.

Everything that we need is enabled on Basic level.

Change is done for clamp 1 only.
2022-03-09 23:24:44 +01:00
TheLastRar 134242973b Config: Set a sane default value for HddSizeSectors 2022-03-09 10:07:54 +00:00
TheLastRar 92900d8dc8 Config: Fix manual subnet mask save/load 2022-03-09 10:07:54 +00:00
Ziemas 7a970e1d00 Filesystem: Properly convert stat return to bool.
Two of the overloads where wrong.
2022-03-09 09:33:51 +00:00
143 changed files with 5926 additions and 3473 deletions
+5
View File
@@ -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/**/*'
+4 -10
View File
@@ -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.
-1
View File
@@ -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)
+7 -10
View File
@@ -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
+10 -15
View File
@@ -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
View File
@@ -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.
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -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,
+2 -33
View File
@@ -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)
-1
View File
@@ -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
+6 -5
View File
@@ -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
View File
@@ -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.
-8
View File
@@ -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!
+11
View File
@@ -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);
+62
View File
@@ -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
View File
@@ -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;
-1
View File
@@ -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">
-3
View File
@@ -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>
+1 -1
View File
@@ -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);
}
-12
View File
@@ -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>
-12
View File
@@ -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>
-188
View File
@@ -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
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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());
}
+4 -4
View File
@@ -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);
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
+5 -4
View File
@@ -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);
+31 -8
View File
@@ -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>
+1 -1
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
+111
View File
@@ -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()
+18
View File
@@ -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;
};
+14 -3
View File
@@ -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)
+1
View File
@@ -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();
+49 -13
View File
@@ -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;
}
+11
View File
@@ -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
+1 -1
View File
@@ -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;
}
+122
View File
@@ -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
View File
@@ -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;
};
+10
View File
@@ -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;
+3
View File
@@ -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
View File
@@ -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";
+1 -1
View File
@@ -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
View File
@@ -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;
-57
View File
@@ -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
View File
@@ -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
View File
@@ -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();
};
+12
View File
@@ -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()
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
};
-52
View File
@@ -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
}
-30
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+12 -2
View File
@@ -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);
+59 -5
View File
@@ -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);
+9 -7
View File
@@ -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
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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;
+4 -5
View File
@@ -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;
}
}
}
+65 -112
View File
@@ -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;
}
+2 -9
View File
@@ -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;
+75 -43
View File
@@ -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;
+18 -46
View File
@@ -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;
-9
View File
@@ -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];
+1 -1
View File
@@ -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;
+1 -60
View File
@@ -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
+23 -6
View File
@@ -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);
+6 -1
View File
@@ -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;
+22 -23
View File
@@ -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;
+18 -4
View File
@@ -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);
+3 -3
View File
@@ -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:
+3 -3
View File
@@ -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
+37 -36
View File
@@ -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);
+342
View File
@@ -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
}
+15
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
};
+9
View File
@@ -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())
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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