Compare commits

...

192 Commits

Author SHA1 Message Date
KamFretoZ 42ce97aca5 Qt: Clean up Setup Wizard's labels 2026-07-11 15:41:27 +02:00
KamFretoZ a4df5c300e Qt/Launcher: Fix StartupWMClass Value 2026-07-11 15:41:27 +02:00
KamFretoZ 4bf51e735a Qt: Add Create PCSX2 shortcut option to setup wizard 2026-07-11 15:41:27 +02:00
KamFretoZ d7e7c8164c Qt: Decouple CreateShortcut from the ShortcutCreationDialog 2026-07-11 15:41:27 +02:00
TJnotJT eb5e3fcd13 GS/HW: Make all vertices the same color in certain flat shading cases.
Fixes issues with AA1 with flat shading.
2026-07-10 10:16:51 +02:00
TheLastRar 8f8968cbb1 Deps: Revert workaround for MSVC ICE with PlutoVG
This reverts commit 7ade24fc77.
2026-07-09 18:40:47 -04:00
Silent ac83e93426 GameDB: Update Gran Turismo entries to use anchors and overrides 2026-07-09 15:53:38 -04:00
Silent 78d0cf4a4f YAML: Add support for resolving anchors, and use it for GameDB 2026-07-09 15:53:38 -04:00
lightningterror 2444c6090b GS: Fix Compiler warnings. 2026-07-09 18:06:50 +02:00
JordanTheToaster 7e49bc5a50 3rdparty: Update Vulkan-Headers to v1.4.356 2026-07-09 12:05:39 +02:00
JordanTheToaster 457719d0cc Deps: Update libjpegturbo to 3.2.0 2026-07-09 12:05:39 +02:00
JordanTheToaster c3e63d5a0e 3rdparty: Update CPUInfo to commit b1a5d63 2026-07-09 12:05:39 +02:00
TJnotJT 8c1b3f8ce3 QT: Remove ROV tabstop in graphics advanced section.
No longer used in this part of the GUI.
2026-07-09 11:44:18 +02:00
TJnotJT 55b37b794c GS:DX12: Index pipelines in correct shader cache table. 2026-07-09 11:43:44 +02:00
TJnotJT 1aca396e34 GS/DX12: Make sure null texture has correct descriptor type for slot. 2026-07-09 11:43:17 +02:00
PCSX2 Bot cb000a5101 [ci skip] Qt: Update Base Translation. 2026-07-08 20:48:48 -04:00
chaoticgd 1ae2a96747 Debugger: Allow strings to be edited from the symbol trees 2026-07-08 15:02:23 +02:00
SternXD 6834086c37 Achievements: Improve subset sidebar nav/focus behavior 2026-07-08 15:00:49 +02:00
SternXD b33b493c6e FullscreenUI: Use locale time on landing page instead of 24 hour 2026-07-08 15:00:49 +02:00
SternXD 437fe1e442 FullscreenUI: Move game info and cover art to top left of pause menu 2026-07-08 15:00:49 +02:00
TellowKrinkle 2a348dcff9 GS:MTL: Add ROV support for RW Textures Tier 1 hardware 2026-07-08 14:08:29 +02:00
TellowKrinkle 2821986fb2 GS:MTL: Implement ROV 2026-07-08 14:08:29 +02:00
TellowKrinkle 1a13f9707b GS:MTL: GPU ROV feature detection 2026-07-08 14:08:29 +02:00
TellowKrinkle ff1b47942c GS:MTL: Reduce unneccessary texture rebinds 2026-07-08 14:08:29 +02:00
TellowKrinkle 13e4973b48 GS:MTL: Fix texture flags 2026-07-08 14:08:29 +02:00
raid273 fd46054fb7 GameDB: Remove cpuSpriteRender from Mana-Khemia 2026-07-04 21:51:16 +02:00
raid273 f618f39bee GameDB: Various fixes 2026-07-04 21:51:16 +02:00
JordanTheToaster 603486ad2f Deps: Update SDL3 to v3.4.12 2026-07-04 21:49:31 +02:00
lightningterror a4b11651a4 GS: Better handle imgui texture creation hazards. 2026-07-04 20:40:55 +02:00
PCSX2 Bot b6e9a04433 [ci skip] Qt: Update Base Translation. 2026-07-03 20:22:06 -04:00
Mrlinkwii 05a2bbbf35 GameDB: remove gamefixes from silent hill 3 2026-07-03 16:09:21 -04:00
Oleg Tolmatcev 16b6572826 Misc: another COM code cleanup 2026-07-03 16:08:58 -04:00
Mrlinkwii 806f06fba6 Achievements: Rename softcore to Casual 2026-07-03 16:07:16 -04:00
TJnotJT 7a90caedec GS/HW: Force depth ROV if alpha test needs depth feedback. 2026-07-02 19:46:47 +02:00
TJnotJT 017b4d07da GS/HW: Improve ROV discard behavior.
Try to avoid color/depth write when it's discarded.
2026-07-02 19:46:47 +02:00
lightningterror 05015bc476 GS/HW: Better handle some texture creation hazards.
BeginDSAsRT and ConvertTextureTypeROVSingle make sure the textures are actually created.
2026-07-02 11:24:08 +02:00
lightningterror 1f0f3b92b3 GS/DX12: Expand the fb optimization hit detection. 2026-07-02 11:21:49 +02:00
JordanTheToaster fe3ce7f578 GameDB: Various Gran Turismo fixes 2026-07-01 11:40:37 +02:00
PCSX2 Bot 51c995168a [ci skip] PAD: Update to latest controller database. 2026-06-29 18:57:33 +02:00
PCSX2 Bot f83e4ff4bf [ci skip] Qt: Update Base Translation. 2026-06-28 20:26:52 -04:00
chaoticgd b67e793283 PINE: Disallow access to pages with custom VTLB handlers 2026-06-28 16:46:13 -04:00
chaoticgd d87ec54a5f VTLB: Rewrite vtlb_ramRead function template
Previously the declaration didn't match the definition, so you couldn't
actually call it.
2026-06-28 16:46:13 -04:00
TJnotJT a6b1040caf GS: Update target TEX0 on a move if buffer width is increased.
Co-authored-by: refractionpcsx2
2026-06-28 21:51:10 +02:00
TheLastRar 9650c4b79a GS/HW: Tweak AF shader 2026-06-28 21:46:04 +02:00
wxvu 3f8eb5adf0 GameDB: Various fixes 2026-06-28 13:58:29 -04:00
TJnotJT 99a78f9a55 GS: Add GPU pipeline stats to OSD.
Adds vertex shader and pixel shader invocations.
2026-06-28 12:39:56 -04:00
TJnotJT c3ace64205 GS/HW: Change prefer_unused_texture parameter to prefer_reuse in GSDevice::FetchSurface().
prefer_reuse is the opposite of prefer_unused_texture, so all corresponding arguments are inverted.
2026-06-28 12:13:38 -04:00
TJnotJT 3b2c1ec6e3 GS/DX12: Fix DX12 renderpass restart optimization rebase error. 2026-06-28 12:13:38 -04:00
TJnotJT dba432639e GS/VK: Detect max supported framebuffer dimensions for null framebuffer. 2026-06-28 12:13:38 -04:00
TJnotJT 166c4491c2 GS/HW: ROV activation revisions.
Force color ROV if depth ROV is used.
Only force color/depth ROV if the draw actually uses both color/depth (fixes a bug with temporary DS for stencil being used as a ROV).
Simplify the ROV activation heuristic a bit (removed unused variables, simplify barrier counting, etc.)
2026-06-28 12:13:38 -04:00
TJnotJT d1cd5a62ed GS/HW: ROV revisions.
Use GSTexture::FeedbackTarget RTs by default (not GSTexture::ShaderWriteTarget).
Do ROV type conversion for both color and depth (if needed).
Make sure the formats for ROV actually support UAV/storage image.
Change 'PSSetUnorderedAccess' to 'PSSetROVs' for clarity.
DX12: Use enum names instead of raw constants in PSSetShaderResource().
Some string format cleanup to GL_*() macros.
VK: Do not enable ROV if FB fetch is available.
Other misc cosmetic changes such as whitespace, etc.

Co-authored-by: TellowKrinkle
2026-06-28 12:13:38 -04:00
TJnotJT b11a406519 GS: Change GSTexture::Type to GSTexture::Usage
Usage fits more cleanly with API flags.
Also separates out feedback and write usage from render target.

Co-authored-by: TellowKrinkle
2026-06-28 12:13:38 -04:00
TJnotJT c7042e1877 GS/HW: Use CreateCompatible() in texture cache to propagate correct formats.
Co-authored-by: TellowKrinkle
2026-06-28 12:13:38 -04:00
Devloon 896e0b82c2 Qt: show full game titles in grid mode.
Added UI element with new icon to toggle showing full game titles by wrapping around to the next line.
2026-06-28 11:55:18 -04:00
chaoticgd 7856757087 AudioStream: Don't compare uninitialized padding 2026-06-27 16:51:29 -04:00
chaoticgd b0ce5d7582 Debugger: Fix some uninitialized variables 2026-06-27 16:51:29 -04:00
Ziemas e23416aa92 IR3000A: Use SmallString with Zydis formatter 2026-06-27 14:26:08 -04:00
Ziemas 9a9cfca706 IR5900: Use SmallString with Zydis formatter 2026-06-27 14:26:08 -04:00
Ziemas 59feb88ef7 IR5900: fix recMemcheck to not cache loaded reg
This functions calls out of the JIT, so it will get stomped on by
something else.
2026-06-27 14:26:08 -04:00
Ziemas 247cda0e26 IR3000A: DUMP_BLOCKS: Symbolize text ptr relative 2026-06-27 14:26:08 -04:00
Ziemas 9f3233224e IR5900: DUMP_BLOCKS: Symbolize text ptr relative 2026-06-27 14:26:08 -04:00
PCSX2 Bot ef14238b4e [ci skip] Qt: Update Base Translation. 2026-06-27 09:02:47 +02:00
lightningterror 13b7345189 GS/HW: Fix bbox when using aa1.
Suggested by TJ.
2026-06-27 09:02:11 +02:00
JordanTheToaster 48ca476a2f GameSummary: Redirect to redump.info 2026-06-26 10:35:51 +02:00
JordanTheToaster 57ef8e7c25 GameDB: Various fixes 2026-06-26 10:35:51 +02:00
JordanTheToaster d09ce46700 GameDB: Add AA1 rec to the DB 2026-06-26 10:35:51 +02:00
JordanTheToaster 3afc1c2663 GameDB: Add AAT rec to the DB 2026-06-26 10:35:51 +02:00
JordanTheToaster 5821762870 ImGuiOverlay: Add ROV to GPU status 2026-06-26 10:35:51 +02:00
JordanTheToaster 86b7a19f19 GS/DX11/DX12: Report ROV support in log 2026-06-26 10:35:51 +02:00
PCSX2 Bot cc85cef17c [ci skip] Qt: Update Base Translation. 2026-06-25 20:54:38 -04:00
SternXD 5f08f523c2 Qt: Add sorting to memory card list 2026-06-25 21:04:04 +02:00
KamFretoZ b612959682 Qt/GameListBackground: Dont keep re-encoding frames 2026-06-25 21:03:07 +02:00
KamFretoZ aea83d5ece Qt/GameListBackground: Make focus detection less agressive
So that custom background can still play when child window is focused
2026-06-25 21:03:07 +02:00
KamFretoZ 07aa5786e5 Qt/GameListBackground: Small fixes
fix possibly wrong DPR calculation on HiDPI display and add processBackgroundFrame() to showEvent
2026-06-25 21:03:07 +02:00
KamFretoZ 5bd70aff90 Qt/GameListBackground: Make highlight semi-transparent
and a semi-transparent backdrop to "No Game Detected" screen
2026-06-25 21:03:07 +02:00
KamFretoZ 22b8d52311 Qt/GameListBackground: Auto adjust gamelist type icon color 2026-06-25 21:03:07 +02:00
KamFretoZ ee6c7e6286 Qt/GameListBackground: Auto adjust gamelist text color 2026-06-25 21:03:07 +02:00
lightningterror 66ea4c4967 GS/DX11: Backport ds as rt from GL for depth feedback.
Doing gpu depth copies is quite slower on dx11, so let's
use the ds as rt behavior from GL which would allow us
to treat them as rt copies instead which are faster.
2026-06-25 20:56:58 +02:00
lightningterror a6769818fd GS/HW: DATE setup changes.
DATE one can run on complex alpha test if there's no overlap.
Make sure DATE one doesn't run if complex alpha test is enabled and there's overlap.
Enable DATE barrier on complex alpha test if there's overlap.
2026-06-24 16:02:45 +02:00
refractionpcsx2 95535215aa GS/TC: Use ValidOverlaps check for exact Tex is RT matches 2026-06-23 03:13:35 +02:00
TJnotJT eadb46c5ac GS/DX12: Remove unnecessary UAV state and simplify texture unbinding. 2026-06-23 02:59:46 +02:00
PCSX2 Bot b2b7943dbe [ci skip] PAD: Update to latest controller database. 2026-06-22 14:48:03 -04:00
dependabot[bot] a0a261db50 Bump actions/checkout in the ci-deps group across 1 directory
Bumps the ci-deps group with 1 update in the / directory: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 6 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-22 10:26:36 -04:00
lightningterror 8e73dea7e2 GS/GL: Fix recent aa1 shader regressions.
Line was accidentally removed and macro typo.
2026-06-21 01:17:52 +02:00
TJnotJT e2a3670d65 GS/HW: Adjust line AA1 blur with upscaling. 2026-06-20 22:09:33 +02:00
jasaaved 342db51523 FullscreenUI: Fix controller navigation breaking after Big Picture Mode window resized
If Big Picture mode's window is resized too greatly, the window's NavRectRel are stale and controller navigation breaks. This also happens when toggling fullscreen.

Now we force a nav reinit when resizing.
2026-06-19 23:40:42 +02:00
chaoticgd 414f1660ed Memory: Fix typo in SysMemory::DumpMemoryMap 2026-06-19 16:43:10 -04:00
PCSX2 Bot cd9530eec3 [ci skip] Qt: Update Base Translation. 2026-06-16 02:41:59 +02:00
PCSX2 Bot 53675cf5ce [ci skip] PAD: Update to latest controller database. 2026-06-15 19:42:12 +02:00
Bobby Smith e0566546c6 OSD: Include "Show GPU Debug Info" when using the "De/Select All" buttons 2026-06-15 18:41:24 +02:00
TJnotJT 6c4a8efe25 QT/FSUI: Set ROV default off and move the settings to Graphics>Rendering.
ROV may have negative performance impacts on some games/systems so allow users to opt in. Also it needs further revision/refinement.
2026-06-15 18:31:08 +02:00
lightningterror a8db6587cb Qt: Disable VK Rov barrier toggle on other renderers. 2026-06-15 18:28:55 +02:00
PCSX2 Bot 1d8fb3d407 [ci skip] Qt: Update Base Translation. 2026-06-13 20:29:29 -04:00
Oleg Tolmatcev 2d09d53805 Misc: clean up COM code 2026-06-13 15:40:44 -04:00
SternXD f5310f0ca4 Achievements: Group leaderboards by subset and tracking state 2026-06-13 15:35:03 -04:00
KamFretoZ 972fcfa0f0 Qt: Fix Formatting 2026-06-13 15:34:46 -04:00
KamFretoZ b0582f6ea3 Qt/OSD: Fix GPU stats not updating when Show GPU Usage settings arent enabled 2026-06-13 15:34:46 -04:00
KamFretoZ 8b6c28b374 Qt/Shortcut: Use Nearest-Neighbor scaling for icon preview
No need to get fancy
2026-06-13 15:34:46 -04:00
KamFretoZ 0a3c27765d Achievements: Simplify sound effects playback 2026-06-13 15:34:46 -04:00
KamFretoZ 040a8b8fc6 Qt: Fix Status Bar visibility when Languange Changes 2026-06-13 15:34:46 -04:00
KamFretoZ 9f67f72d3c Qt: Revamp the status bar 2026-06-13 15:34:46 -04:00
jasaaved 04438ace57 FullscreenUI: Fix analog requiring neutral position to reset
Before, the analog stick would have to reset to the neutral position before allowing the cursor to move again. This has been fixed, cursor moves now once it crosses 45 degrees towards a new axis.
2026-06-13 15:34:27 -04:00
jasaaved e16236e450 FullscreenUI: Cleanup formatting
Fix formatting in pre-existing code
2026-06-13 15:34:27 -04:00
jasaaved 3807517e02 FullscreenUI: Fix analog/dpad nav state shared across controllers
Per-controller state was stored in function-local statics, meaning one controller could corrupt the input state of another. Move to a per-controller map keyed by controller ID.
2026-06-13 15:34:27 -04:00
jasaaved ab8bd8e754 FullscreenUI: Add analog navigation for Xinput and Dinput 2026-06-13 15:34:27 -04:00
jasaaved 65d63085f8 FullscreenUI: Fix analog stick input bursting
Analog inputs are now read as single event once it passes the deadzone / threshold.
2026-06-13 15:34:27 -04:00
jasaaved 2c8ecc3ea7 FullscreenUI: Remove diagonal navigation
Removing diagonal navigation makes moving across titles feel smoother and works closer to Steam's big picture mode.
2026-06-13 15:34:27 -04:00
jasaaved 5fbc79c466 FullscreenUI: Add analog control 2026-06-13 15:34:27 -04:00
SternXD 8fe4183856 FullscreenUI: Fix volume sliders to match Qts max 200%
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-13 15:33:29 -04:00
SternXD 0d52608f1d FullscreenUI: Add some missing settings from Qt
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-13 15:33:29 -04:00
SternXD 5df3c54b84 FullscreenUI: Move Achievement page/login to settings file
I guess this was an oversight when I was splitting up FullscreenUI

Signed-off-by: SternXD <stern@sidestore.io>
2026-06-13 15:33:29 -04:00
SternXD b2db2e71b6 FullscreenUI: Correct default label for Division Rounding Mode
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-13 15:33:29 -04:00
SternXD 7978370b39 Common/Emitter: Inline _xMovRtoR into xImpl_Mov operator
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-13 09:34:53 -04:00
TheLastRar d187c61599 GS/DX12: Enable tight alignment 2026-06-12 18:08:03 -04:00
TheLastRar fa745a58b2 3rdparty: Update D3D12MA to v3.2.0 2026-06-12 18:08:03 -04:00
lightningterror 16592f3a6e GS/GL: Expand the fb optimization hit detection. 2026-06-12 22:29:47 +02:00
lightningterror 2b5d3510c3 GS/DX11: Expand the fb optimization hit detection. 2026-06-12 22:29:47 +02:00
TJnotJT 76f690d96e GS/DX11/GL: Fix sample area calculation for RT/DS sampling hazard. 2026-06-12 18:58:17 +02:00
PCSX2 Bot d5f75c9e42 [ci skip] Qt: Update Base Translation. 2026-06-10 02:26:28 +02:00
lightningterror 13d3491571 GS/GL: Add basic clip control fallback.
When GLAD_GL_ARB_clip_control is not supported then change
the vertex shader depth ranges to make sure it matches -1 1.
2026-06-10 01:35:46 +02:00
lightningterror 8a6d6818fb Revert "GS/GL: Discard stencil when not in use while using depth."
This reverts commit e0365c1d10.
2026-06-10 01:35:46 +02:00
Ty d7c1cbbc4e GHActions: Report flathub cronjob errors to discord 2026-06-09 18:35:41 -04:00
JordanTheToaster 5644ca09c4 GameDB: Dragon Quest VIII fixes 2026-06-09 22:39:03 +02:00
JordanTheToaster 863307d871 ImGuiOverlays: Add missing space to draw buffering 2026-06-09 22:39:03 +02:00
lightningterror 904a0942f0 GS/DX11: Destroy uav resources. 2026-06-09 09:22:07 +02:00
lightningterror 7f20ff60ea GS/DX11: Fallback to regular OMSetRenderTargets if no uav are active. 2026-06-09 09:22:07 +02:00
lightningterror 1ce246e05d GS/DX11: Reuse frame buffer optimizations for uav/rov. 2026-06-09 09:22:07 +02:00
PCSX2 Bot f79461b407 [ci skip] Qt: Update Base Translation. 2026-06-09 03:53:56 +02:00
PCSX2 Bot bbfe32e963 [ci skip] PAD: Update to latest controller database. 2026-06-09 03:53:42 +02:00
wxvu 06c67b0319 GameDB: Various fixes
GameDB: Various fixes

GameDB: Various fixes

GameDB: Various fixes
2026-06-07 15:25:08 -04:00
Adso Castro c68753d776 Qt: Add blank lines around the macro window title block 2026-06-07 15:24:54 -04:00
Adso Castro 15172303e4 Qt: Use multitap slot names for the first slot too
The binding widget and macro window titles keyed off sioPadIsMultitapSlot(),
which is only true for the multitap-exclusive slots (B/C/D), so the first slot
of each port (1A/2A) was shown without its slot letter while multitap was
enabled. Decide based on whether multitap is enabled for the port instead, so
all four slots are labelled consistently with the side list.
2026-06-07 15:24:54 -04:00
Adso Castro 9017ad626d Qt: Remove translator comments from controller binding titles 2026-06-07 15:24:54 -04:00
Adso Castro ef18567d9f Qt: Show multitap slot names in controller binding titles
The ControllerBindingWidget group box title and the ControllerMacroWidget
window title always read "Controller Port N", ignoring multitap slots. When
a multitap is enabled the side list already shows "Controller Port NA/B/C/D"
(handled in ControllerSettingsWindow), but the per-slot widget titles did not
follow suit, so every multitap slot looked like it referred to the base port.

Use sioPadIsMultitapSlot()/sioConvertPadToPortAndSlot() to render the same
"Controller Port NA" style labels in both titles, mirroring the existing
list-item logic.

Fixes #14529

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:24:54 -04:00
SternXD d0c2097cd4 Qt/ImGui: Use macOS keyboard behaviors
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 15:02:57 -04:00
SternXD b5ed65ddd6 Qt/ImGui: Add clipboard support and fix modfier keys
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 15:02:57 -04:00
Adso Castro 673917ae66 Qt: Fix game list view toggle with an empty game list
When the game list is empty the placeholder page is shown, and showGameList()/
showGameGrid() returned early before persisting the GameListGridView setting, so
toggling the view had no effect. updateToolbar() also derived the button state
from the current stack index, which is always the placeholder page when empty,
so the toolbar never reflected the selected mode.

Persist the preference before the early-out and base the toolbar state on the
saved setting, so switching views works (and is remembered for when games are
added) even while the list is empty.

Fixes #13220

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:54:17 -04:00
SternXD e31f57a02f GameList: Create covers directory if missing before downloading covers
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 14:53:56 -04:00
SternXD ee57382d6e FullscreenUI: Implement cover download support
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 14:53:56 -04:00
SternXD 6683f84da0 Tests: remove stubs that aren't needed
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 14:53:56 -04:00
SternXD d2cb0aaf63 GSRunner: Remove noops that aren't needed
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 14:53:56 -04:00
SternXD 51a5e10b4e Qt: Remove unneeded BPM handling code
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 14:53:56 -04:00
refractionpcsx2 c2dfc10c18 GS/HW: Fix draw offsets in shuffles 2026-06-07 14:41:23 -04:00
refractionpcsx2 6628de5262 GS/HW: Only expand overlaps on page boundaries 2026-06-07 14:41:23 -04:00
refractionpcsx2 37f2837a55 GS/TC: Don't pre-downscale if native palette draw is enabled 2026-06-07 14:41:03 -04:00
refractionpcsx2 4b76157b9e GS/TC: Add new HW Readback option to force full download 2026-06-07 14:39:52 -04:00
refractionpcsx2 3b2962fe1c GS: Fix some more draw buffering edgecases 2026-06-07 14:21:48 -04:00
refractionpcsx2 20721b05fb GS: Fix temp rect handling 2026-06-07 14:21:48 -04:00
refractionpcsx2 75187d69c6 GS: Fix dirty reg handling 2026-06-07 14:21:48 -04:00
chaoticgd 3df128d9f9 PINE: Ignore SIGPIPE properly on macOS 2026-06-06 09:59:21 -04:00
PCSX2 Bot 426d77a932 [ci skip] Qt: Update Base Translation. 2026-06-04 02:56:46 +02:00
lightningterror b3b1ff0f50 GS/GL: Expand fb copy fallbacks.
Add nv extension GLAD_GL_NV_copy_image copy fallback.

Re add fbo copy fallback when no copy extension is supported and expand it for both color and depth.
2026-06-04 02:22:17 +02:00
KamFretoZ 88029a1411 Qt/FSUI: Enable ROV by default 2026-06-03 20:07:26 +02:00
JordanTheToaster 57e46f07fe Deps: Update SDL3 to v3.4.10 2026-06-03 05:38:57 +02:00
TJnotJT 254d955f89 GS/HW: Fix PS selector bits format in debug strings.
Fix the formatting since bit width went from 96 to 128.
2026-06-03 04:52:54 +02:00
TJnotJT e490685b42 GS/HW: Improve unordered access flag handling for RTs.
Only for DX11, which doesn't track resource state otherwise.
2026-06-03 03:26:24 +02:00
TJnotJT 7b0c39a20d GS/GL: Remove ROV support.
Buggy on multiple systems, even with various barrier hacks.
2026-06-03 03:26:24 +02:00
TJnotJT 059d631a6d QT/FSUI: Add ROV options to FSUI and QT.
Co-authored-by: SternXD
2026-06-03 03:26:24 +02:00
TJnotJT 7c255bd58d GS/VK: Fix for broken feedback transitions on Windows RDNA2.
Co-authored-by: TheLastRar
2026-06-03 03:26:24 +02:00
TJnotJT bbcd5ec25e GS/HW: ROV support. 2026-06-03 03:26:24 +02:00
chaoticgd 5369d6b38e CMake: Fix typo in BuildParameters.cmake 2026-06-02 07:14:55 -04:00
chaoticgd b3834427bc PINE: Don't test for a valid VM when checking emulator version 2026-06-01 23:55:19 +02:00
PCSX2 Bot d7002433a2 [ci skip] PAD: Update to latest controller database. 2026-06-01 23:54:08 +02:00
Dreadmoth e1291d5b7c Misc: Correct Hz symbol case 2026-06-01 09:51:12 -04:00
chaoticgd e1fd632ba3 CI: Add a debug build to the Linux build matrix 2026-06-01 09:26:11 -04:00
refractionpcsx2 fbaba52bc2 GS/HW: Fix bad assert causing debug build failure 2026-06-01 12:08:28 +01:00
PCSX2 Bot 224e82f33e [ci skip] Qt: Update Base Translation. 2026-06-01 05:27:17 +02:00
TJnotJT 8df49d7676 GS/HW: Fix a number of compiler warnings.
Missing default case in switch statement.
Signed/unsigned implict conversion.
Unused variables.
Hidden virtual overloaded function.
2026-05-31 22:38:31 +02:00
JordanTheToaster 88d8c561db Settings: Enable Skip Duplicate Frames by default 2026-05-31 15:11:02 -04:00
Tom Pritchard 78697466e0 Cli: Fix gamearg processing when using fast boot 2026-05-31 15:10:35 -04:00
chaoticgd 5e150cd3eb SaveState: Fix compression settings 2026-05-31 15:10:17 -04:00
chaoticgd 23dd23b468 CMake: Don't ship Qt Network on Windows 2026-05-31 15:10:06 -04:00
KamFretoZ 7d47dab728 Translation: Add Azərbaycanca 2026-05-31 15:02:29 -04:00
TJnotJT 74f2f73ce6 GS/HW: Use an enum instead of boolean to specify nearest/bilinear filtering. 2026-05-31 18:43:01 +02:00
TJnotJT 1e2f60a9b8 GS/HW: Ignore HW bilinear flag for shaders that do SW bilinear.
Co-authored-by: TellowKrinkle
2026-05-31 18:43:01 +02:00
TJnotJT bf892e9ece GS/HW: Treat depth input as R32 color input in convert shaders.
Co-authored-by: TellowKrinkle
2026-05-31 18:43:01 +02:00
TJnotJT a44fe80caa GS/HW: Refactor shader copy and texture formats.
Make it easier to add new depth formats, and code cleanup.

Co-authored-by: TellowKrinkle
2026-05-31 18:43:01 +02:00
chaoticgd 093287f6bf Console: Improve logic for outputting color codes 2026-05-31 15:35:22 +02:00
lightningterror e0365c1d10 GS/GL: Discard stencil when not in use while using depth.
Backport from DX12, clear the stencil when it's not used.
2026-05-30 22:02:09 +02:00
Ty 6cb2086dfc GHActions: Don't automatically undraft stable releases 2026-05-30 17:11:07 +02:00
TJnotJT 3f4b424200 GS/TC: Refactor/cleanup preload function. 2026-05-30 10:47:47 -04:00
refractionpcsx2 051fdd55b0 GS: Fix xy_tail buffers when draw buffering is enabled 2026-05-30 15:40:58 +02:00
refractionpcsx2 29f4318ef8 GS/TC: Fix combine targets scale and valid areas 2026-05-30 15:40:44 +02:00
lightningterror 30d7fed0e5 GS/DX12: Discard stencil when not in use while using depth.
Because the same texture is shared and used for both depth and stencil we want to discard when the stencil is not used instead of no access as that gives a validation error.
2026-05-30 15:02:22 +02:00
refractionpcsx2 f0177a879c HW/TC: Only make 8bit target sources temporary if they have MIP levels 2026-05-30 15:00:54 +02:00
refractionpcsx2 88af1e54a4 GS/HW: Downscale target before 8bit conversion 2026-05-30 15:00:54 +02:00
PCSX2 Bot d3ba0542f2 [ci skip] Qt: Update Base Translation. 2026-05-30 14:53:01 +02:00
TJnotJT 4d25bdcabb GS/DX11/GL: Adapt full barrier multidraw FB copy for sampling RT/DS hazards. 2026-05-30 14:52:42 +02:00
TJnotJT 02c5f8f648 GS/HW: Fix offset draw vertex trace/draw rect. 2026-05-29 23:27:33 +02:00
SternXD fc23783224 FullscreenUI: Move AA1 from SW only path 2026-05-29 21:29:07 +02:00
TheLastRar 7ade24fc77 Deps: Workaround MSVC ICE with PlutoVG 2026-05-28 19:49:11 +02:00
Heitof db16fa4403 GameDB: Remove Radio Helicopter II patches 2026-05-27 23:52:23 +02:00
249 changed files with 42297 additions and 8582 deletions
@@ -11,7 +11,7 @@ jobs:
name: "Update Base Translation"
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Update Base Translation
run: ./.github/workflows/scripts/common/update_base_translation.sh
@@ -9,7 +9,7 @@ jobs:
if: github.repository == 'PCSX2/pcsx2'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Get Latest DB and Prepare DB File
run: |
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install Packages
run: |
+18 -1
View File
@@ -51,7 +51,7 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
set-safe-directory: ${{ env.GITHUB_WORKSPACE }}
# 10 here, since the odds of having 10 untagged commits in a row should be slim to none
@@ -157,4 +157,21 @@ jobs:
with:
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
path: ci-artifacts
report-error:
runs-on: ubuntu-latest
needs: build_linux
if: always() && needs.build_linux.result == 'failure' && inputs.publish == true
steps:
- uses: actions/checkout@v7
- name: Push Discord Webhook
env:
OWNER: PCSX2
REPO: pcsx2
DISCORD_BUILD_WEBHOOK: ${{ secrets.DISCORD_BUILD_WEBHOOK }}
GITHUB_TOKEN: ${{ github.token }}
run: |
cd ./.github/workflows/scripts/releases/announce-release
npm ci
FLATHUB_FAILURE=1 node index.js
+12
View File
@@ -20,6 +20,18 @@ jobs:
cmakeflags: ""
buildAppImage: true
secrets: inherit
build_linux_debug:
name: "Debug"
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Debug Build"
artifactPrefixName: "PCSX2-linux-Qt-x64-debug"
compiler: clang
cmakeflags: ""
buildAppImage: true
cmakeBuildType: Debug
secrets: inherit
build_linux_flatpak:
name: "Flatpak"
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
+6 -2
View File
@@ -39,6 +39,10 @@ on:
required: false
type: boolean
default: false
cmakeBuildType:
required: false
type: string
default: Release
jobs:
build_linux:
@@ -55,7 +59,7 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
@@ -129,7 +133,7 @@ jobs:
ADDITIONAL_CMAKE_ARGS: ${{ inputs.cmakeflags }}
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_BUILD_TYPE="${{ inputs.cmakeBuildType }}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DCMAKE_PREFIX_PATH="$HOME/deps" \
-DCMAKE_C_COMPILER=clang-17 \
+1 -1
View File
@@ -52,7 +52,7 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
# actions/checkout elides tags, fetch them primarily for releases
- name: Fetch Tags
+3 -2
View File
@@ -35,7 +35,7 @@ jobs:
outputs:
new_tag: ${{ steps.tag_version.outputs.new_tag }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
# Docs - https://github.com/mathieudutour/github-tag-action
- name: Bump Version and Push Tag
@@ -176,7 +176,7 @@ jobs:
name: "Upload Artifacts"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Prepare Artifact Folder
run: mkdir ./ci-artifacts/
@@ -209,6 +209,7 @@ jobs:
gh release upload "${TAG_VAL}" ${{ github.WORKSPACE }}/ci-artifacts/out/* --repo PCSX2/pcsx2 --clobber
- name: Publish Release
if: github.event_name != 'workflow_dispatch' || inputs.is_prerelease == 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
@@ -23,11 +23,11 @@ QTAPNG=1.3.0
FFMPEG=8.1
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
LIBJPEGTURBO=3.1.4.1
LIBJPEGTURBO=3.2.0
LIBPNG=1.6.58
LIBWEBP=1.6.0
NVENC=13.0.19.0
SDL=SDL3-3.4.8
SDL=SDL3-3.4.12
LZ4=1.10.0
VULKAN=1.4.328.1
ZSTD=1.5.7
@@ -57,10 +57,10 @@ f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG
b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a ffmpeg-$FFMPEG.tar.xz
96e5c2d7f2c482a60d5804da48a2eb9a0db0719b2c65dcc169fbfdcf37f3a45d libbacktrace-$LIBBACKTRACE.tar.gz
ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
6f30092cef9fb839779646608f4ee14ae3cbac989c47fa05e841b0841f09878e libjpeg-turbo-$LIBJPEGTURBO.tar.gz
28eb403f51f0f7405249132cecfe82ea5c0ef97f1b32c5a65828814ae0d34775 libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
f07b958a9ac5020fb7a44cadb957f658b2149c3c8abb4f63145fac9303249db7 $SDL.tar.gz
eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 libpng-$LIBPNG-apng.patch.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
13da39edb3a40ed9713ae390ca89faa2f1202c9dda869ef306a8d4383e242bee nv-codec-headers-$NVENC.tar.gz
@@ -14,8 +14,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL3-3.4.8.tar.gz",
"sha256": "e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba"
"url": "https://libsdl.org/release/SDL3-3.4.12.tar.gz",
"sha256": "f07b958a9ac5020fb7a44cadb957f658b2149c3c8abb4f63145fac9303249db7"
}
],
"cleanup": [
@@ -3,7 +3,7 @@ Version=1.0
Terminal=false
Type=Application
Name=PCSX2
StartupWMClass=PCSX2
StartupWMClass=pcsx2-qt
GenericName=PlayStation 2 Emulator
Comment=Sony PlayStation 2 emulator
Exec=pcsx2-qt
@@ -47,12 +47,12 @@ QT=6.11.1
QTAPNG=1.3.0
FREETYPE=2.14.3
SDL=SDL3-3.4.8
SDL=SDL3-3.4.12
HARFBUZZ=14.2.0
ZSTD=1.5.7
LZ4=1.10.0
LIBPNG=1.6.58
LIBJPEGTURBO=3.1.4.1
LIBJPEGTURBO=3.2.0
LIBWEBP=1.6.0
FFMPEG=8.1
MOLTENVK=1.4.1
@@ -93,14 +93,14 @@ b2bf6c6845ac175ed7f819145483ba4676f617aaa6a5012c8efee63c8bbac413 qtimageformats
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
36bc4f1cc413335368ee656c42afca65c5a3987e8768cc28cf11ba775e785a5f freetype-$FREETYPE.tar.xz
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
f07b958a9ac5020fb7a44cadb957f658b2149c3c8abb4f63145fac9303249db7 $SDL.tar.gz
c652d5d94971031654ab3989891a490a895d3e3f2b71171c62692b28e94b1b93 harfbuzz-$HARFBUZZ.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
28eb403f51f0f7405249132cecfe82ea5c0ef97f1b32c5a65828814ae0d34775 libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 libpng-$LIBPNG-apng.patch.gz
ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
6f30092cef9fb839779646608f4ee14ae3cbac989c47fa05e841b0841f09878e libjpeg-turbo-$LIBJPEGTURBO.tar.gz
b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a ffmpeg-$FFMPEG.tar.xz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c MoltenVK-$MOLTENVK.tar.gz
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
@@ -24,12 +24,12 @@ QT=6.11.1
QTAPNG=1.3.0
FREETYPE=2.14.3
SDL=SDL3-3.4.8
SDL=SDL3-3.4.12
HARFBUZZ=14.2.0
ZSTD=1.5.7
LZ4=1.10.0
LIBPNG=1.6.58
LIBJPEGTURBO=3.1.4.1
LIBJPEGTURBO=3.2.0
LIBWEBP=1.6.0
FFMPEG=8.1
MOLTENVK=1.4.1
@@ -69,14 +69,14 @@ b2bf6c6845ac175ed7f819145483ba4676f617aaa6a5012c8efee63c8bbac413 qtimageformats
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
36bc4f1cc413335368ee656c42afca65c5a3987e8768cc28cf11ba775e785a5f freetype-$FREETYPE.tar.xz
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
f07b958a9ac5020fb7a44cadb957f658b2149c3c8abb4f63145fac9303249db7 $SDL.tar.gz
c652d5d94971031654ab3989891a490a895d3e3f2b71171c62692b28e94b1b93 harfbuzz-$HARFBUZZ.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
28eb403f51f0f7405249132cecfe82ea5c0ef97f1b32c5a65828814ae0d34775 libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 libpng-$LIBPNG-apng.patch.gz
ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
6f30092cef9fb839779646608f4ee14ae3cbac989c47fa05e841b0841f09878e libjpeg-turbo-$LIBJPEGTURBO.tar.gz
b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a ffmpeg-$FFMPEG.tar.xz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c v$MOLTENVK.tar.gz
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
@@ -38,39 +38,54 @@ const octokit = new Octokit({
}
});
if (process.env.TAG_VAL === undefined || process.env.TAG_VAL === "") {
console.log(`Not announcing - TAG_VAL not defined`);
process.exit(1);
let embed;
if (process.env.FLATHUB_FAILURE === undefined)
{
if (process.env.TAG_VAL === undefined || process.env.TAG_VAL === "") {
console.log(`Not announcing - TAG_VAL not defined`);
process.exit(1);
}
const { data: releaseInfo } = await octokit.rest.repos.getReleaseByTag({
owner: owner,
repo: repo,
tag: process.env.TAG_VAL,
});
if (releaseInfo === undefined) {
console.log(`Not announcing - could not locate release with tag ${process.env.TAG_VAL}`);
process.exit(1);
}
if (!releaseInfo.prerelease) {
console.log("Not announcing - release was not a pre-release (aka a Nightly)");
process.exit(0);
}
// Publish Webhook
embed = new MessageEmbed()
.setColor('#FF8000')
.setTitle('New PCSX2 Nightly Build Available!')
.setDescription("To download the latest or previous builds, [visit the official downloads page](https://pcsx2.net/downloads/).")
.addFields(
{ name: 'Version', value: releaseInfo.tag_name, inline: true },
{ name: 'Installation Steps', value: '[See Here](https://pcsx2.net/docs/category/setup)', inline: true },
{ name: 'Included Changes', value: releaseInfo.body, inline: false }
);
console.log(embed);
}
else
{
// Flathub upload failure
const { data: releaseInfo } = await octokit.rest.repos.getReleaseByTag({
owner: owner,
repo: repo,
tag: process.env.TAG_VAL,
});
if (releaseInfo === undefined) {
console.log(`Not announcing - could not locate release with tag ${process.env.TAG_VAL}`);
process.exit(1);
embed = new MessageEmbed()
.setColor('#FF0000')
.setTitle('PCSX2 Failed to Build/Upload to FlatHub')
.setDescription("Please check the latest Flathub build job to determine the root cause.")
console.log(embed);
}
if (!releaseInfo.prerelease) {
console.log("Not announcing - release was not a pre-release (aka a Nightly)");
process.exit(0);
}
// Publish Webhook
const embed = new MessageEmbed()
.setColor('#FF8000')
.setTitle('New PCSX2 Nightly Build Available!')
.setDescription("To download the latest or previous builds, [visit the official downloads page](https://pcsx2.net/downloads/).")
.addFields(
{ name: 'Version', value: releaseInfo.tag_name, inline: true },
{ name: 'Installation Steps', value: '[See Here](https://pcsx2.net/docs/category/setup)', inline: true },
{ name: 'Included Changes', value: releaseInfo.body, inline: false }
);
console.log(embed);
// Get all webhooks, simple comma-sep string
const webhookUrls = process.env.DISCORD_BUILD_WEBHOOK.split(",");
+4 -4
View File
@@ -60,8 +60,8 @@ set QTAPNG=1.3.0
set FREETYPE=2.14.3
set HARFBUZZ=14.2.0
set SDL=SDL3-3.4.8
set LIBJPEGTURBO=3.1.4.1
set SDL=SDL3-3.4.12
set LIBJPEGTURBO=3.2.0
set LIBPNG=1658
set LIBPNGLONG=1.6.58
set LZ4=1.10.0
@@ -92,9 +92,9 @@ call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip bb2f83255706b1c92d731541c7cefaf98bb5b93e8f76d16f6deda05225ff20ee || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1658.zip b32f170855dbbe3e6d9e645af40b538137041773672c3ba3e02db5816c82d376 || goto error
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 6f30092cef9fb839779646608f4ee14ae3cbac989c47fa05e841b0841f09878e || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 506206e02f90c1f37e048eacaf9e8a3a7dc682fd27783eb0ff15a7d2dcc9c2af || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 3d4de8967a49c0451e775a0c1e9022092c19fdef41ba38a83fcf031c5a6496e2 || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
+16 -4
View File
@@ -77,8 +77,8 @@ set LIBX264=b35605ace3ddf7c1a5d67a2eb553f034aef41d55
set FREETYPE=2.14.3
set HARFBUZZ=14.2.0
set SDL=SDL3-3.4.8
set LIBJPEGTURBO=3.1.4.1
set SDL=SDL3-3.4.12
set LIBJPEGTURBO=3.2.0
set LIBPNG=1658
set LIBPNGLONG=1.6.58
set LZ4=1.10.0
@@ -97,6 +97,7 @@ set SHADERC_SPIRVHEADERS=58006c901d1d5c37dece6b6610e9af87fa951375
set SHADERC_SPIRVTOOLS=6337eb62cadd7d124ac6789bf39c0f71148f0a73
set AGILITYSDK=1.619.2
set DXHEADERS=1.619.1
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 3529cc37297a5a7aae4486843b9fd41c30df1d79a770f85e240b537dcc327ca5 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 37fba768f2780580dfae535ad6654cb9dc0bf2272e71b9b9781988de9ed0dac0 || goto error
@@ -119,9 +120,9 @@ call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip bb2f83255706b1c92d731541c7cefaf98bb5b93e8f76d16f6deda05225ff20ee || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1658.zip b32f170855dbbe3e6d9e645af40b538137041773672c3ba3e02db5816c82d376 || goto error
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 6f30092cef9fb839779646608f4ee14ae3cbac989c47fa05e841b0841f09878e || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 506206e02f90c1f37e048eacaf9e8a3a7dc682fd27783eb0ff15a7d2dcc9c2af || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 3d4de8967a49c0451e775a0c1e9022092c19fdef41ba38a83fcf031c5a6496e2 || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
@@ -129,6 +130,7 @@ call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 4fe4e48f28aa80171b2166d45c0976ab0f21eecedb52cd4c3ef73b5afb48fac9 || goto error
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
call :downloadfile "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" eb92d90bb23b2ec23410c41d791e41dbdbec942ab946924d1fdcb31eac6f0735 || goto error
call :downloadfile "DirectX-Headers-%DXHEADERS%.zip" "https://github.com/microsoft/DirectX-Headers/archive/v%DXHEADERS%.zip" 9eb8b102a90a42e4ea72a825f7d249d55ec90d164f030966c9b7784b93374927 || goto error
call :downloadfile "rapidyaml-%RAPIDYAML%-src.zip" "https://github.com/biojppm/rapidyaml/releases/download/v%RAPIDYAML%/rapidyaml-%RAPIDYAML%-src.zip" 96276f55b9fa7837ac8f3f72fd52965879cbb5d5d2e6af548c69a177fb078304 || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" f9401cc5cb36c276cd1e072b6595dbd728148e8dba389e50f7339e2d388dbc08 || goto error
@@ -506,6 +508,16 @@ if %DEBUG%==1 (
)
cd .. || goto error
rem DirectX Headers include a CMakeList file, which is absent in the Nuget package
echo Unpacking DirectX Headers
rmdir /S /Q "DirectX-Headers-%DXHEADERS%"
%SEVENZIP% x "DirectX-Headers-%DXHEADERS%.zip" || goto error
cd "DirectX-Headers-%DXHEADERS%" || goto error
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DDXHEADERS_BUILD_TEST=OFF -DDXHEADERS_BUILD_GOOGLE_TEST=OFF -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo Building shaderc...
rmdir /S /Q "shaderc-%SHADERC%"
%SEVENZIP% x "shaderc-%SHADERC%.zip" || goto error
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: windows-2025-vs2026
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Verify VS Project Files
run: .github\workflows\scripts\windows\validate-vs-filters.ps1
+1 -1
View File
@@ -56,7 +56,7 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Configure MSBuild Clang Version
if: inputs.configuration != 'CMake'
+2
View File
@@ -361,6 +361,8 @@ enum cpuinfo_uarch {
cpuinfo_uarch_raptor_cove = 0x0010020F,
/** Intel Redwood Cove microarchitecture (Granite Rapids). */
cpuinfo_uarch_redwood_cove = 0x00100210,
/** Intel Coyote Cove microarchitecture. */
cpuinfo_uarch_coyote_cove = 0x00100211,
/** Pentium 4 with Willamette, Northwood, or Foster cores. */
cpuinfo_uarch_willamette = 0x00100300,
+3
View File
@@ -1,3 +1,6 @@
/* for syscall() */
#define _DEFAULT_SOURCE
#include <stdbool.h>
#include <stddef.h>
+2
View File
@@ -36,6 +36,7 @@ enum cpuinfo_arm_chipset_vendor {
cpuinfo_arm_chipset_vendor_texas_instruments,
cpuinfo_arm_chipset_vendor_unisoc,
cpuinfo_arm_chipset_vendor_wondermedia,
cpuinfo_arm_chipset_vendor_google,
cpuinfo_arm_chipset_vendor_max,
};
@@ -73,6 +74,7 @@ enum cpuinfo_arm_chipset_series {
cpuinfo_arm_chipset_series_unisoc_t,
cpuinfo_arm_chipset_series_unisoc_ums,
cpuinfo_arm_chipset_series_wondermedia_wm,
cpuinfo_arm_chipset_series_google_tensor,
cpuinfo_arm_chipset_series_max,
};
+1 -1
View File
@@ -366,7 +366,7 @@ CPUINFO_INTERNAL struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_f
CPUINFO_INTERNAL struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_hardware_chipname(
const char ro_hardware_chipname[restrict static CPUINFO_BUILD_PROP_VALUE_MAX]);
CPUINFO_INTERNAL struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_soc_model(
const char ro_soc_model[restrict static CPUINFO_BUILD_PROP_VALUE_MAX]);
const char soc_model[restrict static CPUINFO_BUILD_PROP_VALUE_MAX]);
#else
CPUINFO_INTERNAL struct cpuinfo_arm_chipset cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_revision(
const char proc_cpuinfo_revision[restrict static CPUINFO_REVISION_VALUE_MAX]);
+61 -10
View File
@@ -3492,9 +3492,20 @@ struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_chipname(
};
}
/*
* Decodes chipset name from ro.soc.model Android system property.
*
* @param[in] soc_model - ro.soc.model value.
*
* @returns Decoded chipset name. If chipset could not be decoded, the resulting
* structure would use `unknown` vendor and series identifiers.
*/
struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_soc_model(
const char soc_model[restrict static CPUINFO_BUILD_PROP_VALUE_MAX]) {
struct cpuinfo_arm_chipset chipset;
struct cpuinfo_arm_chipset chipset = {
.vendor = cpuinfo_arm_chipset_vendor_unknown,
.series = cpuinfo_arm_chipset_series_unknown,
};
const size_t soc_model_length = strnlen(soc_model, CPUINFO_BUILD_PROP_VALUE_MAX);
const char* soc_model_end = soc_model + soc_model_length;
@@ -3516,10 +3527,28 @@ struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_soc_model(
return chipset;
}
return (struct cpuinfo_arm_chipset){
.vendor = cpuinfo_arm_chipset_vendor_unknown,
.series = cpuinfo_arm_chipset_series_unknown,
};
if (soc_model[0] != '\0') {
if (strncmp(soc_model, "Tensor", 6) == 0) {
chipset.vendor = cpuinfo_arm_chipset_vendor_google;
chipset.series = cpuinfo_arm_chipset_series_google_tensor;
const char* suffix_start = soc_model + 6;
while (*suffix_start == ' ') {
suffix_start++;
}
const size_t suffix_length = strnlen(suffix_start, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
if (suffix_length > 0) {
strncpy(chipset.suffix, suffix_start, suffix_length);
}
return chipset;
} else if (strncmp(soc_model, "GS201", 5) == 0) {
chipset.vendor = cpuinfo_arm_chipset_vendor_google;
chipset.series = cpuinfo_arm_chipset_series_google_tensor;
strncpy(chipset.suffix, "G2", 2);
return chipset;
}
}
return chipset;
}
#endif /* __ANDROID__ */
@@ -3858,6 +3887,7 @@ static const char* chipset_vendor_string[cpuinfo_arm_chipset_vendor_max] = {
[cpuinfo_arm_chipset_vendor_texas_instruments] = "Texas Instruments",
[cpuinfo_arm_chipset_vendor_unisoc] = "Unisoc",
[cpuinfo_arm_chipset_vendor_wondermedia] = "WonderMedia",
[cpuinfo_arm_chipset_vendor_google] = "Google",
};
/* Map from ARM chipset series ID to its string representation */
@@ -3895,6 +3925,7 @@ static const char* chipset_series_string[cpuinfo_arm_chipset_series_max] = {
[cpuinfo_arm_chipset_series_unisoc_t] = "T",
[cpuinfo_arm_chipset_series_unisoc_ums] = "UMS",
[cpuinfo_arm_chipset_series_wondermedia_wm] = "WM",
[cpuinfo_arm_chipset_series_google_tensor] = "Tensor",
};
/* Convert chipset name represented by cpuinfo_arm_chipset structure to a string
@@ -3913,14 +3944,35 @@ void cpuinfo_arm_chipset_to_string(
const char* vendor_string = chipset_vendor_string[vendor];
const char* series_string = chipset_series_string[series];
const uint32_t model = chipset->model;
const size_t suffix_length = strnlen(chipset->suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
if (model == 0) {
if (series == cpuinfo_arm_chipset_series_unknown) {
strncpy(name, vendor_string, CPUINFO_ARM_CHIPSET_NAME_MAX);
if (suffix_length > 0) {
if (series == cpuinfo_arm_chipset_series_unknown) {
snprintf(
name,
CPUINFO_ARM_CHIPSET_NAME_MAX,
"%s %.*s",
vendor_string,
(int)suffix_length,
chipset->suffix);
} else {
snprintf(
name,
CPUINFO_ARM_CHIPSET_NAME_MAX,
"%s %s %.*s",
vendor_string,
series_string,
(int)suffix_length,
chipset->suffix);
}
} else {
snprintf(name, CPUINFO_ARM_CHIPSET_NAME_MAX, "%s %s", vendor_string, series_string);
if (series == cpuinfo_arm_chipset_series_unknown) {
strncpy(name, vendor_string, CPUINFO_ARM_CHIPSET_NAME_MAX);
} else {
snprintf(name, CPUINFO_ARM_CHIPSET_NAME_MAX, "%s %s", vendor_string, series_string);
}
}
} else {
const size_t suffix_length = strnlen(chipset->suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
snprintf(
name,
CPUINFO_ARM_CHIPSET_NAME_MAX,
@@ -4051,7 +4103,6 @@ static enum cpuinfo_arm_chipset_vendor disambiguate_chipset_vendor(
(vendor_a == cpuinfo_arm_chipset_vendor_spreadtrum && vendor_b == cpuinfo_arm_chipset_vendor_unisoc)) {
return cpuinfo_arm_chipset_vendor_unisoc;
}
return cpuinfo_arm_chipset_vendor_unknown;
}
+3 -3
View File
@@ -256,12 +256,12 @@ void cpuinfo_arm_linux_init(void) {
}
#if defined(__ANDROID__)
struct cpuinfo_android_properties android_properties;
struct cpuinfo_android_properties android_properties = {0};
cpuinfo_arm_android_parse_properties(&android_properties);
#else
char proc_cpuinfo_hardware[CPUINFO_HARDWARE_VALUE_MAX];
char proc_cpuinfo_hardware[CPUINFO_HARDWARE_VALUE_MAX] = {0};
#endif
char proc_cpuinfo_revision[CPUINFO_REVISION_VALUE_MAX];
char proc_cpuinfo_revision[CPUINFO_REVISION_VALUE_MAX] = {0};
if (!cpuinfo_arm_linux_parse_proc_cpuinfo(
#if defined(__ANDROID__)
+49
View File
@@ -11,6 +11,11 @@ void cpuinfo_arm_decode_vendor_uarch(
#endif /* CPUINFO_ARCH_ARM */
enum cpuinfo_vendor vendor[RESTRICT_STATIC 1],
enum cpuinfo_uarch uarch[RESTRICT_STATIC 1]) {
/* Ensure the out-parameters are always initialized, including for
* implementers that are not handled in the switch below. */
*vendor = cpuinfo_vendor_unknown;
*uarch = cpuinfo_uarch_unknown;
switch (midr_get_implementer(midr)) {
case 'A':
*vendor = cpuinfo_vendor_arm;
@@ -438,6 +443,50 @@ void cpuinfo_arm_decode_vendor_uarch(
midr_get_part(midr));
}
break;
case 'a':
*vendor = cpuinfo_vendor_apple;
switch (midr_get_part(midr)) {
case 0x022:
case 0x024:
case 0x028:
*uarch = cpuinfo_uarch_icestorm;
break;
case 0x023:
case 0x025:
case 0x029:
*uarch = cpuinfo_uarch_firestorm;
break;
case 0x032:
case 0x034:
case 0x038:
*uarch = cpuinfo_uarch_blizzard;
break;
case 0x033:
case 0x035:
case 0x039:
*uarch = cpuinfo_uarch_avalanche;
break;
case 0x042:
case 0x044:
case 0x048:
*uarch = cpuinfo_uarch_coll_sawtooth;
break;
case 0x043:
case 0x045:
case 0x049:
*uarch = cpuinfo_uarch_coll_everest;
break;
case 0x052:
*uarch = cpuinfo_uarch_donan_sawtooth;
break;
case 0x053:
*uarch = cpuinfo_uarch_donan_everest;
break;
default:
cpuinfo_log_warning(
"unknown Apple CPU part 0x%03" PRIx32 " ignored", midr_get_part(midr));
}
break;
#if CPUINFO_ARCH_ARM
case 'V':
*vendor = cpuinfo_vendor_marvell;
+9
View File
@@ -307,6 +307,15 @@ static bool transform_token(char* token_start, char* token_end, struct parser_st
}
break;
case 4:
/*
* Erase everything starting with "with" on AMD
* processors, e.g. "AMD Ryzen 5 PRO 6650U with Radeon
* Graphics"
*/
if (erase_matching(token_start, token_length, "with")) {
return false;
}
/* Remember to erase "Dual Core" in "AMD Athlon(tm) 64
* X2 Dual Core Processor 3800+" */
if (memcmp(token_start, "Dual", token_length) == 0) {
+7
View File
@@ -270,8 +270,15 @@ enum cpuinfo_uarch cpuinfo_x86_decode_uarch(
return cpuinfo_uarch_prescott;
}
break;
case 0x12:
switch (model_info->model) {
case 0x01: // Nova Lake P-core (Coyote Cove)
return cpuinfo_uarch_coyote_cove;
}
break;
}
break;
case cpuinfo_vendor_amd:
switch (model_info->family) {
#if CPUINFO_ARCH_X86
-2
View File
@@ -265,8 +265,6 @@ BOOL CALLBACK cpuinfo_x86_windows_init(PINIT_ONCE init_once, PVOID parameter, PV
* APIC order */
const uint32_t core_id = cores_count++;
uint32_t smt_id = 0;
/* Reconstruct core part of APIC ID */
const uint32_t core_apic_id = (core_id & core_bits_mask) << x86_processor.topology.core_bits_offset;
/* Iterate processor groups and set the core & SMT parts of APIC
* ID */
for (uint32_t i = 0; i < core_info->Processor.GroupCount; i++) {
+2
View File
@@ -3,5 +3,7 @@ add_library(D3D12MemAlloc
src/D3D12MemAlloc.cpp
)
target_link_libraries(D3D12MemAlloc PRIVATE Microsoft::DirectX-Headers)
target_include_directories(D3D12MemAlloc PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
disable_compiler_warnings_for_target(D3D12MemAlloc)
+3 -2
View File
@@ -20,6 +20,7 @@
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Project="..\..\common\vsprops\DepsDir.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
@@ -37,9 +38,9 @@
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>D3D12MA_USING_DIRECTX_HEADERS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(DepsIncludeDir);$(ProjectDir)include;$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+12 -3
View File
@@ -24,7 +24,7 @@
/** \mainpage D3D12 Memory Allocator
<b>Version 3.1.0</b> (2026-02-23)
<b>Version 3.2.0</b> (2026-06-05)
Copyright (c) 2019-2026 Advanced Micro Devices, Inc. All rights reserved. \n
License: MIT
@@ -889,10 +889,17 @@ enum POOL_FLAGS
*/
POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED = 0x2,
/** Every allocation made in this pool will be created as a committed resource - will have its own memory block.
There is also an equivalent flag for the entire allocator: D3D12MA::ALLOCATOR_FLAG_ALWAYS_COMMITTED.
*/
POOL_FLAG_ALWAYS_COMMITTED = 0x4,
/** Disables tight resource alignment for all resources created from this pool.
When tight alignment is supported and enabled for the allocator, resources created from custom pools
normally use it automatically. Specify this flag to restore pre-tight-alignment behavior for this pool:
tight alignment won't be requested and small buffers may again be preferred as committed resources.
*/
POOL_FLAG_DONT_USE_TIGHT_ALIGNMENT = 0x8,
// Bit mask to extract only `ALGORITHM` bits from entire set of flags.
POOL_FLAG_ALGORITHM_MASK = POOL_FLAG_ALGORITHM_LINEAR
@@ -1114,7 +1121,8 @@ enum ALLOCATOR_FLAGS
It can also be disabled for a single allocation by using #ALLOCATION_FLAG_STRATEGY_MIN_TIME.
If the tight resource alignment feature is used by the library (which happens automatically whenever supported,
unless you use flag #ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT), then small buffers are not preferred as committed.
unless you use flag #ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT or
#POOL_FLAG_DONT_USE_TIGHT_ALIGNMENT on a custom pool), then small buffers are not preferred as committed.
Long story short, you don't need to specify any of these flags.
The library chooses the most optimal method automatically.
*/
@@ -2892,6 +2900,7 @@ as it is no longer needed.
You can check if the tight alignment it is available in the current system by calling D3D12MA::Allocator::IsTightAlignmentSupported().
You can tell the library to not use it by specifying D3D12MA::ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT.
Custom pools can opt out independently by specifying D3D12MA::POOL_FLAG_DONT_USE_TIGHT_ALIGNMENT.
Typically, you don't need to do any of those.
The library automatically aligns all buffers to at least 256 B, even when the system supports smaller alignment.
+249 -57
View File
@@ -163,6 +163,14 @@ especially to test compatibility with D3D12_RESOURCE_HEAP_TIER_1 on modern GPUs.
#endif
#endif
#ifndef D3D12MA_OPTIONS4_SUPPORTED
#ifdef __ID3D12Device5_INTERFACE_DEFINED__
#define D3D12MA_OPTIONS4_SUPPORTED 1
#else
#define D3D12MA_OPTIONS4_SUPPORTED 0
#endif
#endif
#ifndef D3D12MA_DEBUG_LOG
#define D3D12MA_DEBUG_LOG(format, ...)
/*
@@ -703,6 +711,13 @@ static UINT GetBitsPerPixel(DXGI_FORMAT format)
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
return 32;
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_B8G8R8X8_UNORM:
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8X8_TYPELESS:
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
return 32;
case DXGI_FORMAT_R8G8_TYPELESS:
case DXGI_FORMAT_R8G8_UNORM:
case DXGI_FORMAT_R8G8_UINT:
@@ -717,6 +732,9 @@ static UINT GetBitsPerPixel(DXGI_FORMAT format)
case DXGI_FORMAT_R16_SNORM:
case DXGI_FORMAT_R16_SINT:
return 16;
case DXGI_FORMAT_B5G6R5_UNORM:
case DXGI_FORMAT_B5G5R5A1_UNORM:
return 16;
case DXGI_FORMAT_R8_TYPELESS:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_R8_UINT:
@@ -767,46 +785,175 @@ static ResourceClass ResourceDescToResourceClass(const D3D12_RESOURCE_DESC_T& re
(resDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0;
return isRenderTargetOrDepthStencil ? ResourceClass::RT_DS_Texture : ResourceClass::Non_RT_DS_Texture;
}
static bool ResourceDimensionIsTexture(D3D12_RESOURCE_DIMENSION dimension)
{
return dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D ||
dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
}
static bool ResourceFlagsContainRenderTargetOrDepthStencil(D3D12_RESOURCE_FLAGS flags)
{
return (flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0;
}
// This algorithm is overly conservative.
struct SmallAlignmentTileShape
{
UINT Width;
UINT Height;
UINT Depth;
};
static bool GetSmallAlignmentTileShape(
D3D12_RESOURCE_DIMENSION dimension,
bool isMsaa,
UINT bitsPerUnit,
SmallAlignmentTileShape& outTileShape)
{
if (isMsaa)
{
if (dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
return false;
switch (bitsPerUnit)
{
case 8: outTileShape = { 256, 256, 1 }; return true;
case 16: outTileShape = { 256, 128, 1 }; return true;
case 32: outTileShape = { 128, 128, 1 }; return true;
case 64: outTileShape = { 128, 64, 1 }; return true;
case 128: outTileShape = { 64, 64, 1 }; return true;
case 256: outTileShape = { 64, 32, 1 }; return true;
case 512: outTileShape = { 32, 32, 1 }; return true;
case 1024: outTileShape = { 32, 16, 1 }; return true;
case 2048: outTileShape = { 16, 16, 1 }; return true;
default: return false;
}
}
switch (dimension)
{
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
switch (bitsPerUnit)
{
case 8: outTileShape = { 4096, 1, 1 }; return true;
case 16: outTileShape = { 2048, 1, 1 }; return true;
case 32: outTileShape = { 1024, 1, 1 }; return true;
case 64: outTileShape = { 512, 1, 1 }; return true;
case 128: outTileShape = { 256, 1, 1 }; return true;
default: return false;
}
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
switch (bitsPerUnit)
{
case 8: outTileShape = { 64, 64, 1 }; return true;
case 16: outTileShape = { 64, 32, 1 }; return true;
case 32: outTileShape = { 32, 32, 1 }; return true;
case 64: outTileShape = { 32, 16, 1 }; return true;
case 128: outTileShape = { 16, 16, 1 }; return true;
default: return false;
}
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
// 4 KB counterparts of the documented 64 KB volume-tile shapes.
switch (bitsPerUnit)
{
case 8: outTileShape = { 16, 16, 16 }; return true;
case 16: outTileShape = { 16, 16, 8 }; return true;
case 32: outTileShape = { 16, 8, 8 }; return true;
case 64: outTileShape = { 8, 8, 8 }; return true;
case 128: outTileShape = { 8, 8, 4 }; return true;
default: return false;
}
default:
return false;
}
}
// This algorithm is overly conservative and applies only to the legacy small-alignment heuristic path.
template<typename D3D12_RESOURCE_DESC_T>
static bool CanUseSmallAlignment(const D3D12_RESOURCE_DESC_T& resourceDesc)
{
if (resourceDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
if (resourceDesc.SampleDesc.Count == 0 ||
resourceDesc.Layout != D3D12_TEXTURE_LAYOUT_UNKNOWN ||
resourceDesc.Width > UINT_MAX)
{
return false;
if ((resourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0)
}
const bool isMsaa = resourceDesc.SampleDesc.Count > 1;
const bool isRtDs = ResourceFlagsContainRenderTargetOrDepthStencil(resourceDesc.Flags);
if (isMsaa && !isRtDs)
{
return false;
if (resourceDesc.SampleDesc.Count > 1)
return false;
if (resourceDesc.DepthOrArraySize != 1)
}
if (!isMsaa &&
isRtDs)
{
return false;
}
UINT sizeX = (UINT)resourceDesc.Width;
UINT sizeY = resourceDesc.Height;
UINT bitsPerPixel = GetBitsPerPixel(resourceDesc.Format);
if (bitsPerPixel == 0)
UINT sizeY = 1;
UINT sizeZ = 1;
UINT bitsPerUnit = GetBitsPerPixel(resourceDesc.Format);
if (bitsPerUnit == 0)
return false;
if (IsFormatCompressed(resourceDesc.Format))
switch (resourceDesc.Dimension)
{
sizeX = DivideRoundingUp(sizeX, 4u);
sizeY = DivideRoundingUp(sizeY, 4u);
bitsPerPixel *= 16;
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
if (isMsaa)
return false;
// For 1D arrays, small-alignment eligibility depends on the mip0 slice size, not array size.
if (IsFormatCompressed(resourceDesc.Format))
return false;
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
// For 2D arrays, small-alignment eligibility depends on mip0 width/height, not array size.
sizeY = resourceDesc.Height;
if (isMsaa && IsFormatCompressed(resourceDesc.Format))
return false;
if (IsFormatCompressed(resourceDesc.Format))
{
sizeX = DivideRoundingUp(sizeX, 4u);
sizeY = DivideRoundingUp(sizeY, 4u);
bitsPerUnit *= 16;
}
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
if (isMsaa)
return false;
sizeY = resourceDesc.Height;
sizeZ = resourceDesc.DepthOrArraySize;
if (IsFormatCompressed(resourceDesc.Format))
{
sizeX = DivideRoundingUp(sizeX, 4u);
sizeY = DivideRoundingUp(sizeY, 4u);
bitsPerUnit *= 16;
}
break;
default:
return false;
}
UINT tileSizeX = 0, tileSizeY = 0;
switch (bitsPerPixel)
{
case 8: tileSizeX = 64; tileSizeY = 64; break;
case 16: tileSizeX = 64; tileSizeY = 32; break;
case 32: tileSizeX = 32; tileSizeY = 32; break;
case 64: tileSizeX = 32; tileSizeY = 16; break;
case 128: tileSizeX = 16; tileSizeY = 16; break;
default: return false;
}
bitsPerUnit *= resourceDesc.SampleDesc.Count;
const UINT tileCount = DivideRoundingUp(sizeX, tileSizeX) * DivideRoundingUp(sizeY, tileSizeY);
return tileCount <= 16;
SmallAlignmentTileShape tileShape = {};
if (!GetSmallAlignmentTileShape(resourceDesc.Dimension, isMsaa, bitsPerUnit, tileShape))
return false;
const UINT64 tileCount =
UINT64(DivideRoundingUp(sizeX, tileShape.Width)) *
UINT64(DivideRoundingUp(sizeY, tileShape.Height)) *
UINT64(DivideRoundingUp(sizeZ, tileShape.Depth));
// Non-MSAA compares 64 KB against 4 KB tiles => 16 pages. MSAA compares 4 MB against 64 KB tiles => 64 pages.
return tileCount <= (isMsaa ? 64 : 16);
}
static bool ValidateAllocateMemoryParameters(
@@ -5988,6 +6135,7 @@ public:
BOOL IsCacheCoherentUMA() const { return m_D3D12Architecture.CacheCoherentUMA; }
bool SupportsResourceHeapTier2() const { return m_D3D12Options.ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2; }
bool IsGPUUploadHeapSupported() const { return m_GPUUploadHeapSupported != FALSE; }
bool IsMsaa64KBAlignedTextureSupported() const { return m_MSAA64KBAlignedTextureSupported != FALSE; }
bool IsTightAlignmentSupported() const { return m_TightAlignmentSupported != FALSE; }
bool IsTightAlignmentEnabled() const { return IsTightAlignmentSupported() && m_UseTightAlignment; }
bool UseMutex() const { return m_UseMutex; }
@@ -6076,7 +6224,7 @@ private:
const bool m_UseMutex;
const bool m_AlwaysCommitted;
const bool m_MsaaAlwaysCommitted;
bool m_PreferSmallBuffersCommitted;
const bool m_PreferSmallBuffersCommitted;
const bool m_UseTightAlignment;
bool m_DefaultPoolsNotZeroed = false;
ID3D12Device* m_Device; // AddRef
@@ -6105,6 +6253,7 @@ private:
DXGI_ADAPTER_DESC m_AdapterDesc;
D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Options;
BOOL m_GPUUploadHeapSupported = FALSE;
BOOL m_MSAA64KBAlignedTextureSupported = FALSE;
BOOL m_TightAlignmentSupported = FALSE;
D3D12_FEATURE_DATA_ARCHITECTURE m_D3D12Architecture;
AllocationObjectAllocator m_AllocationObjectAllocator;
@@ -6121,7 +6270,7 @@ private:
*/
template<typename D3D12_RESOURCE_DESC_T>
bool PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc,
ALLOCATION_FLAGS strategy);
ALLOCATION_FLAGS strategy, bool useTightAlignment) const;
// Allocates and registers new committed resource with implicit heap, as dedicated allocation.
// Creates and returns Allocation object and optionally D3D12 resource.
@@ -6141,6 +6290,7 @@ private:
template<typename D3D12_RESOURCE_DESC_T>
HRESULT CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
const D3D12_RESOURCE_DESC_T* resDesc, // Optional
bool useTightAlignment,
BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted);
// Returns UINT32_MAX if index cannot be calculcated.
@@ -6174,7 +6324,10 @@ private:
template<typename D3D12_RESOURCE_DESC_T>
HRESULT GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc,
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats,
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const;
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo,
bool useTightAlignment) const;
bool IsTightAlignmentEnabled(const ALLOCATION_DESC& allocDesc) const;
bool NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size);
@@ -6277,6 +6430,17 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
}
#endif // #if D3D12MA_OPTIONS16_SUPPORTED
#if D3D12MA_OPTIONS4_SUPPORTED
{
D3D12_FEATURE_DATA_D3D12_OPTIONS4 options4 = {};
hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &options4, sizeof(options4));
if (SUCCEEDED(hr))
{
m_MSAA64KBAlignedTextureSupported = options4.MSAA64KBAlignedTextureSupported;
}
}
#endif // #if D3D12MA_OPTIONS4_SUPPORTED
#if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED
{
D3D12_FEATURE_DATA_TIGHT_ALIGNMENT tightAlignment = {};
@@ -6285,13 +6449,6 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
{
m_TightAlignmentSupported = tightAlignment.SupportTier >= D3D12_TIGHT_ALIGNMENT_TIER_1;
// If tight alignment is supported (checked by the code above) and wasn't disabled by the developer
// (with ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT), disable the preference for creating small buffers as committed,
// as if ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED was specified.
if (IsTightAlignmentEnabled())
{
m_PreferSmallBuffersCommitted = false;
}
}
}
#endif // #if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED
@@ -6490,6 +6647,7 @@ HRESULT AllocatorPimpl::CreateResource(
}
HRESULT hr = E_NOINTERFACE;
const bool useTightAlignment = IsTightAlignmentEnabled(*pAllocDesc);
CREATE_RESOURCE_PARAMS finalCreateParams = createParams;
D3D12_RESOURCE_DESC finalResourceDesc;
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
@@ -6500,7 +6658,7 @@ HRESULT AllocatorPimpl::CreateResource(
{
finalResourceDesc = *createParams.GetResourceDesc();
finalCreateParams.AccessResourceDesc() = &finalResourceDesc;
hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo);
hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo, useTightAlignment);
}
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
@@ -6509,7 +6667,7 @@ HRESULT AllocatorPimpl::CreateResource(
{
finalResourceDesc1 = *createParams.GetResourceDesc1();
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo);
hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo, useTightAlignment);
}
}
#endif
@@ -6521,7 +6679,7 @@ HRESULT AllocatorPimpl::CreateResource(
finalResourceDesc1 = *createParams.GetResourceDesc1();
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
hr = GetResourceAllocationInfo(finalResourceDesc1,
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo);
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo, useTightAlignment);
}
}
#endif
@@ -6547,14 +6705,14 @@ HRESULT AllocatorPimpl::CreateResource(
if (createParams.Variant >= CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
{
hr = CalcAllocationParams<D3D12_RESOURCE_DESC1>(*pAllocDesc, resAllocInfo.SizeInBytes,
createParams.GetResourceDesc1(),
createParams.GetResourceDesc1(), useTightAlignment,
blockVector, committedAllocationParams, preferCommitted);
}
else
#endif
{
hr = CalcAllocationParams<D3D12_RESOURCE_DESC>(*pAllocDesc, resAllocInfo.SizeInBytes,
createParams.GetResourceDesc(),
createParams.GetResourceDesc(), useTightAlignment,
blockVector, committedAllocationParams, preferCommitted);
}
if (FAILED(hr))
@@ -6601,6 +6759,7 @@ HRESULT AllocatorPimpl::AllocateMemory(
bool preferCommitted = false;
HRESULT hr = CalcAllocationParams<D3D12_RESOURCE_DESC>(*pAllocDesc, pAllocInfo->SizeInBytes,
NULL, // pResDesc
false, // useTightAlignment - irrelevant for AllocateMemory
blockVector, committedAllocationParams, preferCommitted);
if (FAILED(hr))
return hr;
@@ -6649,7 +6808,7 @@ HRESULT AllocatorPimpl::CreateAliasingResource(
{
finalResourceDesc = *createParams.GetResourceDesc();
finalCreateParams.AccessResourceDesc() = &finalResourceDesc;
hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo);
hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo, IsTightAlignmentEnabled());
}
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
@@ -6658,7 +6817,7 @@ HRESULT AllocatorPimpl::CreateAliasingResource(
{
finalResourceDesc1 = *createParams.GetResourceDesc1();
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo);
hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo, IsTightAlignmentEnabled());
}
}
#endif
@@ -6670,7 +6829,7 @@ HRESULT AllocatorPimpl::CreateAliasingResource(
finalResourceDesc1 = *createParams.GetResourceDesc1();
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
hr = GetResourceAllocationInfo(finalResourceDesc1,
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo);
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo, IsTightAlignmentEnabled());
}
}
#endif
@@ -7305,13 +7464,14 @@ void AllocatorPimpl::FreeStatsString(WCHAR* pStatsString)
template<typename D3D12_RESOURCE_DESC_T>
bool AllocatorPimpl::PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc,
ALLOCATION_FLAGS strategy)
ALLOCATION_FLAGS strategy, bool useTightAlignment) const
{
// Prefer creating small buffers <= 32 KB as committed, because drivers pack them better,
// while placed buffers require 64 KB alignment.
if(resourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
resourceDesc.Width <= D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT / 2 &&
strategy != ALLOCATION_FLAG_STRATEGY_MIN_TIME && // Creating as committed would be slower.
!useTightAlignment &&
m_PreferSmallBuffersCommitted)
{
return true;
@@ -7526,7 +7686,7 @@ HRESULT AllocatorPimpl::AllocateHeap(
template<typename D3D12_RESOURCE_DESC_T>
HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
const D3D12_RESOURCE_DESC_T* resDesc,
const D3D12_RESOURCE_DESC_T* resDesc, bool useTightAlignment,
BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted)
{
outBlockVector = NULL;
@@ -7599,7 +7759,7 @@ HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, U
{
if (resDesc->SampleDesc.Count > 1 && msaaAlwaysCommitted)
outBlockVector = NULL;
if (!outPreferCommitted && PrefersCommittedAllocation(*resDesc, allocDesc.Flags & ALLOCATION_FLAG_STRATEGY_MASK))
if (!outPreferCommitted && PrefersCommittedAllocation(*resDesc, allocDesc.Flags & ALLOCATION_FLAG_STRATEGY_MASK, useTightAlignment))
outPreferCommitted = true;
}
@@ -7810,12 +7970,13 @@ template<typename D3D12_RESOURCE_DESC_T>
HRESULT AllocatorPimpl::GetResourceAllocationInfo(
D3D12_RESOURCE_DESC_T& inOutResourceDesc,
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats,
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo,
bool useTightAlignment) const
{
#ifdef __ID3D12Device1_INTERFACE_DEFINED__
#if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED
if (IsTightAlignmentEnabled())
if (useTightAlignment)
{
// Don't allow USE_TIGHT_ALIGNMENT together with ALLOW_CROSS_ADAPTER as there is a D3D Debug Layer error:
// D3D12 ERROR: ID3D12Device::GetResourceAllocationInfo: D3D12_RESOURCE_DESC::Flag D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT will be ignored since D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER is set. [ STATE_CREATION ERROR #599: CREATERESOURCE_INVALIDMISCFLAGS]
@@ -7839,7 +8000,7 @@ HRESULT AllocatorPimpl::GetResourceAllocationInfo(
*/
if (inOutResourceDesc.Alignment == 0 &&
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
!IsTightAlignmentEnabled())
!useTightAlignment)
{
outAllocInfo = {
AlignUp<UINT64>(inOutResourceDesc.Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT), // SizeInBytes
@@ -7852,16 +8013,33 @@ HRESULT AllocatorPimpl::GetResourceAllocationInfo(
HRESULT hr = S_OK;
#if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
if (inOutResourceDesc.Alignment == 0 &&
(inOutResourceDesc.Flags & D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT_COPY) == 0 &&
(inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D ||
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) &&
(inOutResourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0
bool trySmallAlignment = false;
if (inOutResourceDesc.Alignment == 0
&& (inOutResourceDesc.Flags & D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT_COPY) == 0
&& inOutResourceDesc.Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN
&& ResourceDimensionIsTexture(inOutResourceDesc.Dimension))
{
// MSAA texture.
if(inOutResourceDesc.SampleDesc.Count > 1)
{
trySmallAlignment = IsMsaa64KBAlignedTextureSupported()
&& ResourceFlagsContainRenderTargetOrDepthStencil(inOutResourceDesc.Flags)
&& inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D;
}
// Non-MSAA texture.
else
{
trySmallAlignment = !ResourceFlagsContainRenderTargetOrDepthStencil(inOutResourceDesc.Flags);
}
}
#if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT == 1
&& CanUseSmallAlignment(inOutResourceDesc)
if(trySmallAlignment)
trySmallAlignment = CanUseSmallAlignment(inOutResourceDesc);
#endif
)
if (trySmallAlignment)
{
/*
The algorithm here is based on Microsoft sample: "Small Resources Sample"
@@ -7886,6 +8064,20 @@ HRESULT AllocatorPimpl::GetResourceAllocationInfo(
inOutResourceDesc, NumCastableFormats, pCastableFormats, outAllocInfo);
}
bool AllocatorPimpl::IsTightAlignmentEnabled(const ALLOCATION_DESC& allocDesc) const
{
if (!IsTightAlignmentEnabled())
return false;
if (allocDesc.CustomPool != NULL &&
(allocDesc.CustomPool->m_Pimpl->GetDesc().Flags & POOL_FLAG_DONT_USE_TIGHT_ALIGNMENT) != 0)
{
return false;
}
return true;
}
bool AllocatorPimpl::NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size)
{
Budget budget = {};
+4 -3
View File
@@ -1,12 +1,13 @@
Copyright 2015-2023 The Khronos Group Inc.
Copyright 2015-2026 The Khronos Group Inc.
Files in this repository fall under one of these licenses:
- `Apache-2.0`
- `MIT`
Note: With the exception of `parse_dependency.py` the files using `MIT` license
also fall under `Apache-2.0`. Example:
Note: With the exception of `parse_dependency.py`, which is based on an
external file, files using the `MIT` license also fall under `Apache-2.0`.
Example:
```
SPDX-License-Identifier: Apache-2.0 OR MIT
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -2
View File
@@ -2,8 +2,7 @@
* Copyright 2015-2023 The Khronos Group Inc.
* Copyright 2015-2023 Valve Corporation
* Copyright 2015-2023 LunarG, Inc.
*
* SPDX-License-Identifier: Apache-2.0
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
#pragma once
+1 -2
View File
@@ -2,8 +2,7 @@
* Copyright 2015-2023 The Khronos Group Inc.
* Copyright 2015-2023 Valve Corporation
* Copyright 2015-2023 LunarG, Inc.
*
* SPDX-License-Identifier: Apache-2.0
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
#pragma once
+1 -2
View File
@@ -3,8 +3,7 @@
//
/*
** Copyright 2014-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
+1 -2
View File
@@ -3,8 +3,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
#include "vk_platform.h"
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
+1 -1
View File
@@ -4,7 +4,7 @@
/*
** Copyright 2015-2026 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
File diff suppressed because it is too large Load Diff
+23 -9
View File
@@ -683,7 +683,7 @@
03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000bd12000010d1000000000000,Sanwa 4Button,a:b0,b:b1,x:b2,y:b3,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,platform:Windows,
03000000bd12000010d1000000000000,Sanwa 4Button,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows,
03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows,
03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows,
@@ -697,14 +697,14 @@
030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,
03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,leftshoulder:b6,lefttrigger:b7,back:b8,start:b9,x:b3,y:b0,platform:Windows,
03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a2,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows,
03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows,
03000000632500002705000000000000,ShanWan Q36,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows,
03000000632500002705000000000000,ShanWan Gamepad,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows,
03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000140300000918000000000000,SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
@@ -733,6 +733,7 @@
03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
03000000381000004114000000000000,SteelSeries Nimbus Cloud,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b5,paddle2:b2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,
03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -776,6 +777,7 @@
030000005f140000c501000000000000,Trust Gamepad,a:b2,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:b3,y:b0,platform:Windows,
03000000b80500000210000000000000,Trust Gamepad,a:b2,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:b3,y:b0,platform:Windows,
030000005f1400002a01000000000000,Trust Predator GM1200,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,x:b3,y:b4,platform:Windows,
03000000580400000a10000000000000,Trust Sight Fighter,a:b0,b:b1,back:b5,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b2,x:b3,y:b4,platform:Windows,
030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows,
03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,
03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
@@ -939,6 +941,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000503200000110000045010000,Atari VCS Classic,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X,
03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X,
03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000e30500008106000000010000,Austgame GameCube Adapter,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:+a4,leftx:a0,lefty:a1,misc3:b5,misc4:b6,rightshoulder:b4,righttrigger:-a4,rightx:a2,righty:a3,start:b7,x:b1,y:b3,platform:Mac OS X,
030000008a3500000102000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
030000008a3500000201000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
@@ -1116,6 +1119,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
03000000381000004114000000010000,SteelSeries Nimbus Cloud,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b5,paddle2:b2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Mac OS X,
05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
@@ -1249,12 +1253,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00001230000011010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001330000011010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001260000011010000,8BitDo Ultimate 2,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux,
03000000c82d00000b31000014010000,8BitDo Ultimate 2,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
05000000c82d00001260000001000000,8BitDo Ultimate 2,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux,
03000000c82d00000a31000014010000,8BitDo Ultimate 2C,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,
03000000c82d00001d30000011010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00001b30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
06000000c82d00000320000007010000,8BitDo Ultimate Wired Controller for Xbox,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
@@ -1276,6 +1284,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000020500000913000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000373500000710000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
19000000010000000100000000010000,Anbernic RG28XX Controller,a:b4,b:b3,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b7,misc1:b1,rightshoulder:b8,leftstick:b12,rightstick:b13,start:b10,x:b5,y:b6,platform:Linux,
03000000190e00000110000010010000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Linux,
03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
@@ -1348,6 +1357,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000373500009710000001020000,GameSir Kaleid Flux,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000373500005810000001020000,GameSir K1,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000ac0500001a06000011010000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000373500000410000044010000,GameSir T4 Kaleid,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,
03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -1446,6 +1456,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
03000000314100001935000000010000,LeadJoy Xeno Plus,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:a4,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00000103000000020000,Logic3 Controller,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,
030000006f0e000001f5000010010000,Logic3 Gamepad,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,
030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -1536,10 +1547,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000853200000706000012010000,Nacon GC100,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,
030000006b140000010c000010010000,Nacon GC400ES,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:Linux,
05000000853200000503000000010000,Nacon MGX Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000085320000180d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
0300000085320000160d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000085320000180d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux,
@@ -1618,6 +1629,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d62000000520000050010000,PowerA Xbox Series Controller,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,
03000000d62000000b20000001010000,PowerA Xbox Series Controller,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,
03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,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,
03000000d62000006520000002010000,PowerA Xbox Series Controller,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,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000250900000017000010010000,PS SS N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
@@ -1751,7 +1763,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e0400008e02000073050000,Speedlink Torid,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,
030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,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,
03000000de280000ff11000001000000,Steam Virtual Gamepad,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,
05000000381000001214000001000000,SteelSeries Free,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a2,righttrigger:a3,platform:Linux,
05000000381000001214000001000000,SteelSeries Free,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000381000004114000000010000,SteelSeries Nimbus Cloud,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b5,paddle2:b2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux,
050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux,
03000000381000003014000075010000,SteelSeries Stratus Duo,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,
03000000381000003114000075010000,SteelSeries Stratus Duo,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,
@@ -1797,9 +1810,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
030000005f140000c501000010010000,Trust Gamepad,a:b2,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:b3,y:b0,platform:Linux,
03000000f51000001370000000000000,Turtle Beach ReactR,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,
03000000f51000001370000000010000,Turtle Beach ReactR,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,
06000000f51000000870000003010000,Turtle Beach Recon,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,
03000000f51000001370000000010000,Turtle Beach ReactR,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
03000000f51000001370000000000000,Turtle Beach ReactR,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
05000000f51000008f01000001000000,Turtle Beach Rematch Nintendo Switch Controller,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,
03000000100800000100000010010000,Twin PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000c0160000e105000010010000,Ultimate Atari Fight Stick,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,platform:Linux,
03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+8
View File
@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-az" viewBox="0 0 640 480">
<path fill="#3f9c35" d="M.1 0h640v480H.1z"/>
<path fill="#ed2939" d="M.1 0h640v320H.1z"/>
<path fill="#00b9e4" d="M.1 0h640v160H.1z"/>
<circle cx="304" cy="240" r="72" fill="#fff"/>
<circle cx="320" cy="240" r="60" fill="#ed2939"/>
<path fill="#fff" d="m384 200 7.7 21.5 20.6-9.8-9.8 20.7L424 240l-21.5 7.7 9.8 20.6-20.6-9.8L384 280l-7.7-21.5-20.6 9.8 9.8-20.6L344 240l21.5-7.7-9.8-20.6 20.6 9.8z"/>
</svg>

After

Width:  |  Height:  |  Size: 501 B

+242 -138
View File
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#if defined(VERTEX_SHADER)
struct VS_INPUT
{
float4 p : POSITION;
@@ -15,6 +17,21 @@ struct VS_OUTPUT
float4 c : COLOR;
};
VS_OUTPUT vs_main(VS_INPUT input)
{
VS_OUTPUT output;
output.p = input.p;
output.t = input.t;
output.c = input.c;
return output;
}
#endif // VERTEX_SHADER
#if defined(PIXEL_SHADER)
cbuffer cb0 : register(b0)
{
float4 BGColor;
@@ -33,11 +50,22 @@ static const float3x3 rgb2yuv =
Texture2D Texture;
SamplerState TextureSampler;
#if HAS_FLOAT32_INPUT
float sample_c(float2 uv)
{
return Texture.Sample(TextureSampler, uv).r;
}
#else
float4 sample_c(float2 uv)
{
return Texture.Sample(TextureSampler, uv);
}
#endif
struct PS_INPUT
{
float4 p : SV_Position;
@@ -45,36 +73,117 @@ struct PS_INPUT
float4 c : COLOR;
};
#if HAS_INTEGER_OUTPUT
#define OUTPUT_TYPE uint
#define OUTPUT_SV SV_Target
#elif HAS_DEPTH_OUTPUT
#define OUTPUT_TYPE float
#define OUTPUT_SV SV_Depth
#elif HAS_FLOAT32_OUTPUT
#define OUTPUT_TYPE float
#define OUTPUT_SV SV_Target
#else
#define OUTPUT_TYPE float4
#define OUTPUT_SV SV_Target
#endif
struct PS_OUTPUT
{
float4 c : SV_Target0;
OUTPUT_TYPE o : OUTPUT_SV;
};
VS_OUTPUT vs_main(VS_INPUT input)
uint rgba8_to_uint(float4 c)
{
VS_OUTPUT output;
output.p = input.p;
output.t = input.t;
output.c = input.c;
return output;
uint4 i = uint4(c * 255.5f) & 0xFFu;
return i.r | (i.g << 8) | (i.b << 16) | (i.a << 24);
}
PS_OUTPUT ps_copy(PS_INPUT input)
uint rgb5a1_to_uint(float4 c)
{
PS_OUTPUT output;
output.c = sample_c(input.t);
return output;
uint4 i = uint4(c * 255.5f) & uint4(0xF8u, 0xF8u, 0xF8u, 0x80u);
return (i.r >> 3) | (i.g << 2) | (i.b << 7) | (i.a << 8);
}
float ps_depth_copy(PS_INPUT input) : SV_Depth
uint depth_to_uint(float d)
{
return sample_c(input.t).r;
return uint(d * exp2(32.0f));
}
float4 uint_to_rgba8(uint i)
{
return float4((i & 0xFFu), ((i >> 8) & 0xFFu), ((i >> 16) & 0xFFu), ((i >> 24) & 0xFFu)) / 255.0f;
}
float4 uint_to_rgb5a1(uint i)
{
return float4(uint4(i << 3, i >> 2, i >> 7, i >> 8) & uint4(0xF8u, 0xF8u, 0xF8u, 0x80u)) / 255.0f;
}
float uint_to_depth32(uint i)
{
return float(i) * exp2(-32.0f);
}
float uint_to_depth24(uint i)
{
return float(i & 0xFFFFFFu) * exp2(-32.0f);
}
float uint_to_depth16(uint i)
{
return float(i & 0xFFFFu) * exp2(-32.0f);
}
float rgba8_to_depth32(float4 val)
{
return uint_to_depth32(rgba8_to_uint(val));
}
float rgba8_to_depth24(float4 val)
{
return uint_to_depth24(rgba8_to_uint(val));
}
float rgba8_to_depth16(float4 val)
{
return uint_to_depth16(rgba8_to_uint(val));
}
float rgb5a1_to_depth16(float4 val)
{
return uint_to_depth16(rgb5a1_to_uint(val));
}
float4 depth32_to_rgba8(float d)
{
return uint_to_rgba8(depth_to_uint(d));
}
float4 depth16_to_rgb5a1(float d)
{
return uint_to_rgb5a1(depth_to_uint(d));
}
float depth32_to_depth24(float d)
{
return uint_to_depth24(depth_to_uint(d));
}
#if defined(__ps_copy__)
OUTPUT_TYPE ps_copy(PS_INPUT input) : OUTPUT_SV
{
return sample_c(input.t);
}
#endif
#if defined(__ps_depth_copy__)
OUTPUT_TYPE ps_depth_copy(PS_INPUT input) : OUTPUT_SV
{
return sample_c(input.t);
}
#endif
#if defined(__ps_downsample_copy__)
PS_OUTPUT ps_downsample_copy(PS_INPUT input)
{
int DownsampleFactor = DOFFSET;
@@ -85,179 +194,134 @@ PS_OUTPUT ps_downsample_copy(PS_INPUT input)
int2 coord = max(int2(input.p.xy) * DownsampleFactor, ClampMin);
PS_OUTPUT output;
output.c = (float4)0;
output.o = (float4)0;
for (int yoff = 0; yoff < DownsampleFactor; yoff++)
{
for (int xoff = 0; xoff < DownsampleFactor; xoff++)
output.c += Texture.Load(int3(coord + int2(xoff * step_multiplier, yoff * step_multiplier), 0));
output.o += Texture.Load(int3(coord + int2(xoff * step_multiplier, yoff * step_multiplier), 0));
}
output.c /= Weight;
output.o /= Weight;
return output;
}
#endif
#if defined(__ps_filter_transparency__)
PS_OUTPUT ps_filter_transparency(PS_INPUT input)
{
PS_OUTPUT output;
float4 c = sample_c(input.t);
output.c = float4(c.rgb, 1.0);
output.o = float4(c.rgb, 1.0);
return output;
}
#endif
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
uint ps_convert_rgba8_16bits(PS_INPUT input) : SV_Target0
#if defined(__ps_convert_rgb5a1_16bits__)
OUTPUT_TYPE ps_convert_rgb5a1_16bits(PS_INPUT input) : OUTPUT_SV
{
uint4 i = sample_c(input.t) * float4(255.5f, 255.5f, 255.5f, 255.5f);
return ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
return rgb5a1_to_uint(sample_c(input.t));
}
#endif
#if defined(__ps_datm1__)
void ps_datm1(PS_INPUT input)
{
clip(sample_c(input.t).a - 127.5f / 255); // >= 0x80 pass
}
#endif
#if defined(__ps_datm0__)
void ps_datm0(PS_INPUT input)
{
clip(127.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass)
}
#endif
#if defined(__ps_datm1_rta_correction__)
void ps_datm1_rta_correction(PS_INPUT input)
{
clip(sample_c(input.t).a - 254.5f / 255); // >= 0x80 pass
}
#endif
#if defined(__ps_datm0_rta_correction__)
void ps_datm0_rta_correction(PS_INPUT input)
{
clip(254.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass)
}
#endif
#if defined(__ps_rta_correction__)
PS_OUTPUT ps_rta_correction(PS_INPUT input)
{
PS_OUTPUT output;
float4 value = sample_c(input.t);
output.c = float4(value.rgb, value.a / (128.25f / 255.0f));
output.o = float4(value.rgb, value.a / (128.25f / 255.0f));
return output;
}
#endif
#if defined(__ps_rta_decorrection__)
PS_OUTPUT ps_rta_decorrection(PS_INPUT input)
{
PS_OUTPUT output;
float4 value = sample_c(input.t);
output.c = float4(value.rgb, value.a * (128.25f / 255.0f));
output.o = float4(value.rgb, value.a * (128.25f / 255.0f));
return output;
}
#endif
#if defined(__ps_colclip_init__)
PS_OUTPUT ps_colclip_init(PS_INPUT input)
{
PS_OUTPUT output;
float4 value = sample_c(input.t);
output.c = float4(round(value.rgb * 255) / 65535, value.a);
output.o = float4(round(value.rgb * 255) / 65535, value.a);
return output;
}
#endif
#if defined(__ps_colclip_resolve__)
PS_OUTPUT ps_colclip_resolve(PS_INPUT input)
{
PS_OUTPUT output;
float4 value = sample_c(input.t);
output.c = float4(float3(uint3(value.rgb * 65535.5) & 255) / 255, value.a);
output.o = float4(float3(uint3(value.rgb * 65535.5) & 255) / 255, value.a);
return output;
}
#endif
uint ps_convert_float32_32bits(PS_INPUT input) : SV_Target0
#if defined(__ps_convert_depth32_32bits__)
OUTPUT_TYPE ps_convert_depth32_32bits(PS_INPUT input) : OUTPUT_SV
{
// Convert a FLOAT32 depth texture into a 32 bits UINT texture
return uint(exp2(32.0f) * sample_c(input.t).r);
// Convert a depth texture into a 32 bits UINT texture
return depth_to_uint(sample_c(input.t));
}
#endif
PS_OUTPUT ps_convert_float32_rgba8(PS_INPUT input)
#if defined(__ps_convert_depth32_rgba8__)
OUTPUT_TYPE ps_convert_depth32_rgba8(PS_INPUT input) : OUTPUT_SV
{
PS_OUTPUT output;
// Convert a FLOAT32 depth texture into a RGBA color texture
uint d = uint(sample_c(input.t).r * exp2(32.0f));
output.c = float4(uint4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / 255.0f;
return output;
// Convert a depth texture into a RGBA color texture
return depth32_to_rgba8(sample_c(input.t));
}
#endif
PS_OUTPUT ps_convert_float16_rgb5a1(PS_INPUT input)
#if defined(__ps_convert_depth16_rgb5a1__)
OUTPUT_TYPE ps_convert_depth16_rgb5a1(PS_INPUT input) : OUTPUT_SV
{
PS_OUTPUT output;
// Convert a FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
uint d = uint(sample_c(input.t).r * exp2(32.0f));
output.c = float4(uint4(d << 3, d >> 2, d >> 7, d >> 8) & uint4(0xf8, 0xf8, 0xf8, 0x80)) / 255.0f;
return output;
// Convert depth (only 16 lsb) into a RGB5A1 color texture
return depth16_to_rgb5a1(sample_c(input.t));
}
#endif
float rgba8_to_depth32(float4 val)
{
uint4 c = uint4(val * 255.5f);
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
}
float rgba8_to_depth24(float4 val)
{
uint3 c = uint3(val.rgb * 255.5f);
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
}
float rgba8_to_depth16(float4 val)
{
uint2 c = uint2(val.rg * 255.5f);
return float(c.r | (c.g << 8)) * exp2(-32.0f);
}
float rgb5a1_to_depth16(float4 val)
{
uint4 c = uint4(val * 255.5f);
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
}
float ps_convert_float32_depth_to_color(PS_INPUT input) : SV_Target0
{
return sample_c(input.t).r;
}
float ps_convert_float32_color_to_depth(PS_INPUT input) : SV_Depth
{
return sample_c(input.t).r;
}
float ps_convert_float32_float24(PS_INPUT input) : SV_Depth
#if defined(__ps_convert_depth32_depth24__)
OUTPUT_TYPE ps_convert_depth32_depth24(PS_INPUT input) : OUTPUT_SV
{
// Truncates depth value to 24bits
uint d = uint(sample_c(input.t).r * exp2(32.0f)) & 0xFFFFFFu;
return float(d) * exp2(-32.0f);
}
float ps_convert_rgba8_float32(PS_INPUT input) : SV_Depth
{
// Convert an RGBA texture into a float depth texture
return rgba8_to_depth32(sample_c(input.t));
}
float ps_convert_rgba8_float24(PS_INPUT input) : SV_Depth
{
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
return rgba8_to_depth24(sample_c(input.t));
}
float ps_convert_rgba8_float16(PS_INPUT input) : SV_Depth
{
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
return rgba8_to_depth16(sample_c(input.t));
}
float ps_convert_rgb5a1_float16(PS_INPUT input) : SV_Depth
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
return rgb5a1_to_depth16(sample_c(input.t));
return depth32_to_depth24(sample_c(input.t));
}
#endif
#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
uint width, height; \
@@ -272,34 +336,57 @@ float ps_convert_rgb5a1_float16(PS_INPUT input) : SV_Depth
float depthBR = CONVERT_FN(Texture.Load(int3(coords.zw, 0))); \
return lerp(lerp(depthTL, depthTR, mix_vals.x), lerp(depthBL, depthBR, mix_vals.x), mix_vals.y);
float ps_convert_rgba8_float32_biln(PS_INPUT input) : SV_Depth
#if defined(__ps_convert_rgba8_depth32__)
OUTPUT_TYPE ps_convert_rgba8_depth32(PS_INPUT input) : OUTPUT_SV
{
// Convert an RGBA texture into a float depth texture
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
#else
return rgba8_to_depth32(sample_c(input.t));
#endif
}
#endif
float ps_convert_rgba8_float24_biln(PS_INPUT input) : SV_Depth
#if defined(__ps_convert_rgba8_depth24__)
OUTPUT_TYPE ps_convert_rgba8_depth24(PS_INPUT input) : OUTPUT_SV
{
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
#else
return rgba8_to_depth24(sample_c(input.t));
#endif
}
#endif
float ps_convert_rgba8_float16_biln(PS_INPUT input) : SV_Depth
#if defined(__ps_convert_rgba8_depth16__)
OUTPUT_TYPE ps_convert_rgba8_depth16(PS_INPUT input) : OUTPUT_SV
{
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
#else
return rgba8_to_depth16(sample_c(input.t));
#endif
}
#endif
float ps_convert_rgb5a1_float16_biln(PS_INPUT input) : SV_Depth
#if defined(__ps_convert_rgb5a1_depth16__)
OUTPUT_TYPE ps_convert_rgb5a1_depth16(PS_INPUT input) : OUTPUT_SV
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
#else
return rgb5a1_to_depth16(sample_c(input.t));
#endif
}
#endif
#if defined(__ps_convert_rgb5a1_8i__)
PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
{
PS_OUTPUT output;
@@ -406,7 +493,7 @@ PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
uint red = (denorm_c.r >> 3) & 0x1Fu;
uint green = (denorm_c.g >> 3) & 0x1Fu;
output.c = (float4)(((float)(((green << 5) | red) & 0xFFu)) / 255.0f);
output.o = (float4)(((float)(((green << 5) | red) & 0xFFu)) / 255.0f);
}
else
{
@@ -414,11 +501,13 @@ PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
uint blue = (denorm_c.b >> 3) & 0x1Fu;
uint alpha = denorm_c.a & 0x80u;
output.c = (float4)(((float)((alpha | (blue << 2) | (green >> 3)) & 0xFFu)) / 255.0f);
output.o = (float4)(((float)((alpha | (blue << 2) | (green >> 3)) & 0xFFu)) / 255.0f);
}
return output;
}
#endif
#if defined(__ps_convert_rgba_8i__)
PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
{
PS_OUTPUT output;
@@ -462,10 +551,12 @@ PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
float4 pixel = Texture.Load(int3(int2(coord), 0));
float2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
output.c = (float4)(sel1); // Divide by something here?
output.o = (float4)(sel1); // Divide by something here?
return output;
}
#endif
#if defined(__ps_convert_clut_4__)
PS_OUTPUT ps_convert_clut_4(PS_INPUT input)
{
// Borrowing the YUV constant buffer.
@@ -478,10 +569,12 @@ PS_OUTPUT ps_convert_clut_4(PS_INPUT input)
int2 final = int2(floor(float2(offset + pos) * scale));
PS_OUTPUT output;
output.c = Texture.Load(int3(final, 0), 0);
output.o = Texture.Load(int3(final, 0), 0);
return output;
}
#endif
#if defined(__ps_convert_clut_8__)
PS_OUTPUT ps_convert_clut_8(PS_INPUT input)
{
float scale = BGColor.x;
@@ -497,10 +590,12 @@ PS_OUTPUT ps_convert_clut_8(PS_INPUT input)
int2 final = int2(floor(float2(offset + pos) * scale));
PS_OUTPUT output;
output.c = Texture.Load(int3(final, 0), 0);
output.o = Texture.Load(int3(final, 0), 0);
return output;
}
#endif
#if defined(__ps_yuv__)
PS_OUTPUT ps_yuv(PS_INPUT input)
{
PS_OUTPUT output;
@@ -515,41 +610,43 @@ PS_OUTPUT ps_yuv(PS_INPUT input)
switch (EMODA)
{
case 0:
output.c.a = i.a;
output.o.a = i.a;
break;
case 1:
output.c.a = Y;
output.o.a = Y;
break;
case 2:
output.c.a = Y / 2.0f;
output.o.a = Y / 2.0f;
break;
case 3:
default:
output.c.a = 0.0f;
output.o.a = 0.0f;
break;
}
switch (EMODC)
{
case 0:
output.c.rgb = i.rgb;
output.o.rgb = i.rgb;
break;
case 1:
output.c.rgb = float3(Y, Y, Y);
output.o.rgb = float3(Y, Y, Y);
break;
case 2:
output.c.rgb = float3(Y, Cb, Cr);
output.o.rgb = float3(Y, Cb, Cr);
break;
case 3:
default:
output.c.rgb = float3(i.a, i.a, i.a);
output.o.rgb = float3(i.a, i.a, i.a);
break;
}
return output;
}
#endif
float ps_stencil_image_init_0(PS_INPUT input) : SV_Target
#if defined(__ps_primid_image_init_0__)
float ps_primid_image_init_0(PS_INPUT input) : SV_Target
{
float c;
if ((127.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass)
@@ -558,8 +655,10 @@ float ps_stencil_image_init_0(PS_INPUT input) : SV_Target
c = float(0x7FFFFFFF);
return c;
}
#endif
float ps_stencil_image_init_1(PS_INPUT input) : SV_Target
#if defined(__ps_primid_image_init_1__)
float ps_primid_image_init_1(PS_INPUT input) : SV_Target
{
float c;
if (sample_c(input.t).a < (127.5f / 255.0f)) // >= 0x80 pass
@@ -568,9 +667,10 @@ float ps_stencil_image_init_1(PS_INPUT input) : SV_Target
c = float(0x7FFFFFFF);
return c;
}
#endif
float ps_stencil_image_init_2(PS_INPUT input)
: SV_Target
#if defined(__ps_primid_image_init_2__)
float ps_primid_image_init_2(PS_INPUT input) : SV_Target
{
float c;
if ((254.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass)
@@ -579,9 +679,10 @@ float ps_stencil_image_init_2(PS_INPUT input)
c = float(0x7FFFFFFF);
return c;
}
#endif
float ps_stencil_image_init_3(PS_INPUT input)
: SV_Target
#if defined(__ps_primid_image_init_3__)
float ps_primid_image_init_3(PS_INPUT input) : SV_Target
{
float c;
if (sample_c(input.t).a < (254.5f / 255.0f)) // >= 0x80 pass
@@ -590,3 +691,6 @@ float ps_stencil_image_init_3(PS_INPUT input)
c = float(0x7FFFFFFF);
return c;
}
#endif
#endif // PIXEL_SHADER
+243 -109
View File
@@ -50,6 +50,12 @@
#define PS_AA1_TRIANGLE_SW_Z 3
#endif
#ifndef PS_ROV_DEPTH_NONE
#define PS_ROV_DEPTH_NONE 0
#define PS_ROV_DEPTH_READ_WRITE 1
#define PS_ROV_DEPTH_READ_ONLY 2
#endif
#ifndef PS_FST
#define PS_IIP 0
#define PS_FST 0
@@ -111,6 +117,8 @@
#define PS_TEX_IS_FB 0
#define PS_AA1 0
#define PS_ABE 0
#define PS_ROV_COLOR 0
#define PS_ROV_DEPTH 0
#endif
#ifndef VS_EXPAND_NONE
@@ -132,6 +140,12 @@
#define SW_DEPTH (NEEDS_DEPTH_FOR_AFAIL || NEEDS_DEPTH_FOR_ZTST || NEEDS_DEPTH_FOR_AA1)
#define ZWRITE (PS_ZFLOOR || PS_ZCLAMP || SW_DEPTH)
#define PS_RETURN_COLOR_ROV (!PS_NO_COLOR && PS_ROV_COLOR)
#define PS_RETURN_COLOR (!PS_NO_COLOR && !PS_ROV_COLOR)
#define PS_RETURN_DEPTH_ROV (PS_ROV_DEPTH == PS_ROV_DEPTH_READ_WRITE)
#define PS_RETURN_DEPTH (ZWRITE && !PS_ROV_DEPTH)
#define PS_ROV_EARLYDEPTHSTENCIL (PS_ROV_COLOR && !PS_ROV_DEPTH && !ZWRITE)
struct VS_INPUT
{
float2 st : TEXCOORD0;
@@ -181,21 +195,26 @@ struct PS_INPUT
struct PS_OUTPUT
{
#define NUM_RTS 0
#if !PS_NO_COLOR
#if PS_DATE == 1 || PS_DATE == 2
float c : SV_Target;
#else
float4 c0 : SV_Target0;
#undef NUM_RTS
#define NUM_RTS 1
#if !PS_NO_COLOR1
float4 c1 : SV_Target1;
#if PS_RETURN_COLOR
#if PS_DATE == 1 || PS_DATE == 2
float c : SV_Target;
#else
float4 c0 : SV_Target0;
#undef NUM_RTS
#define NUM_RTS 1
#if !PS_NO_COLOR1
float4 c1 : SV_Target1;
#endif
#endif
#endif
#endif
#endif
#if ZWRITE
#if PS_RETURN_DEPTH
// In DX12 we do depth feedback loops with a color copy.
#if SW_DEPTH && PS_NO_COLOR1 && DX12
#if SW_DEPTH && PS_NO_COLOR1 && PS_DEPTH_FEEDBACK_SUPPORT == 2
#if NUM_RTS > 0
float depth_color : SV_Target1;
#else
@@ -208,16 +227,31 @@ struct PS_OUTPUT
float depth : SV_Depth;
#endif
#endif
#undef NUM_RTS
};
Texture2D<float4> Texture : register(t0);
Texture2D<float4> Palette : register(t1);
#if !PS_ROV_COLOR
Texture2D<float4> RtTexture : register(t2);
#endif
Texture2D<float> PrimMinTexture : register(t3);
#if !PS_ROV_DEPTH
Texture2D<float> DepthTexture : register(t4);
#endif
SamplerState TextureSampler : register(s0);
#if PS_ROV_COLOR
RasterizerOrderedTexture2D<unorm float4> RtTextureRov : register(u0);
static float4 rov_rt_value;
#endif
#if PS_ROV_DEPTH
RasterizerOrderedTexture2D<float> DepthTextureRov : register(u1);
static float rov_depth_value;
#endif
#ifdef DX12
cbuffer cb1 : register(b1)
#else
@@ -242,8 +276,46 @@ cbuffer cb1
float4x4 DitherMatrix;
float ScaledScaleFactor;
float RcpScaleFactor;
float _pad0_cb1;
float _pad1_cb1;
float LineCovScale;
float _pad2_cb1;
float _pad3_cb1;
float _pad4_cb1;
};
float4 RtLoad(int2 xy)
{
#if PS_ROV_COLOR
return rov_rt_value;
#else
return RtTexture.Load(int3(int2(xy), 0));
#endif
}
float DepthLoad(int2 xy)
{
#if PS_ROV_DEPTH
return rov_depth_value;
#else
return DepthTexture.Load(int3(int2(xy), 0));
#endif
}
void RtWrite(int2 xy, float4 c)
{
#if PS_ROV_COLOR
RtTextureRov[xy] = c;
#endif
}
void DepthWrite(int2 xy, float d)
{
#if PS_ROV_DEPTH
DepthTextureRov[xy] = d;
#endif
}
#if (PS_AUTOMATIC_LOD != 1) && (PS_MANUAL_LOD == 1)
float manual_lod(float uv_w)
{
@@ -275,23 +347,28 @@ bool2 nan_or_inf(float2 xy)
float4 sample_c_af(float2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = any(nan_or_inf(uv)) ? float2(0, 0) : uv;
uv = any(nan_or_inf(uv)) ? float2(0.0f, 0.0f) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// And https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_filter_anisotropic.txt
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
float2 sz;
Texture.GetDimensions(sz.x, sz.y);
float2 dX = ddx(uv) * sz;
float2 dY = ddy(uv) * sz;
float length_x = length(dX);
float length_y = length(dY);
// Calculate Ellipse Transform
bool d_zero = length(dX) == 0 || length(dY) == 0;
bool d_par = (dX.x * dY.y - dY.x * dX.y) == 0;
bool d_per = dot(dX, dY) == 0;
bool d_zero = length_x < 0.001f || length_y < 0.001f;
float f = (dX.x * dY.y - dX.y * dY.x);
bool d_par = f < 0.001f;
bool d_per = dot(dX, dY) < 0.001f;
bool d_inf_nan = any(nan_or_inf(dX) | nan_or_inf(dY));
if (!(d_zero || d_par || d_per || d_inf_nan))
@@ -299,42 +376,49 @@ float4 sample_c_af(float2 uv, float uv_w)
float A = dX.y * dX.y + dY.y * dY.y;
float B = -2 * (dX.x * dX.y + dY.x * dY.y);
float C = dX.x * dX.x + dY.x * dY.x;
float f = (dX.x * dY.y - dY.x * dX.y);
float F = f * f;
float p = A - C;
float q = A + C;
float t = sqrt(p * p + B * B);
float sqrt_num_plus = sqrt(F * (t + p));
float sqrt_num_minus = sqrt(F * (t - p));
float inv_sqrt_denom_plus = rsqrt(t * (q + t));
float inv_sqrt_denom_minus = rsqrt(t * (q - t));
float signB = sign(B);
float2 new_dX = float2(
sqrt(F * (t + p) / (t * (q + t))),
sqrt(F * (t - p) / (t * (q + t))) * sign(B)
sqrt_num_plus * inv_sqrt_denom_plus,
sqrt_num_minus * inv_sqrt_denom_plus * signB
);
float2 new_dY = float2(
sqrt(F * (t - p) / (t * (q - t))) * -sign(B),
sqrt(F * (t + p) / (t * (q - t)))
sqrt_num_minus * inv_sqrt_denom_minus * -signB,
sqrt_num_plus * inv_sqrt_denom_minus
);
d_inf_nan = any(nan_or_inf(new_dX) | nan_or_inf(new_dY));
if (!d_inf_nan)
{
dX = new_dX;
dY = new_dY;
length_x = length(dX);
length_y = length(dY);
}
}
// Compute AF values
float squared_length_x = dX.x * dX.x + dX.y * dX.y;
float squared_length_y = dY.x * dY.x + dY.y * dY.y;
float determinant = abs(dX.x * dY.y - dX.y * dY.x);
bool is_major_x = squared_length_x > squared_length_y;
float squared_length_major = is_major_x ? squared_length_x : squared_length_y;
float length_major = sqrt(squared_length_major);
bool is_major_x = length_x > length_y;
float length_major = is_major_x ? length_x : length_y;
float length_minor = is_major_x ? length_y : length_x;
float aniso_ratio;
float length_lod;
float2 aniso_line;
if (length_major <= 1.0f)
{
// A zero length_major would result in NaN Lod and break sampling.
@@ -342,57 +426,44 @@ float4 sample_c_af(float2 uv, float uv_w)
// Perform isotropic filtering instead.
aniso_ratio = 1.0f;
length_lod = length_major;
aniso_line = float2(0, 0);
aniso_line = float2(0.0f, 0.0f);
}
else
{
float norm_major = 1.0f / length_major;
float2 aniso_line_dir = float2(
(is_major_x ? dX.x : dY.x) * norm_major,
(is_major_x ? dX.y : dY.y) * norm_major
);
aniso_ratio = squared_length_major / determinant;
float2 aniso_line_dir = is_major_x ? dX : dY;
// Calculate the minor length of the ellipse for Lod, while also clamping the ratio of anisotropy.
if (aniso_ratio > PS_ANISOTROPIC_FILTERING)
{
// ratio is clamped - Lod is based on ratio (preserves area)
aniso_ratio = PS_ANISOTROPIC_FILTERING;
length_lod = length_major / PS_ANISOTROPIC_FILTERING;
}
else
{
// ratio not clamped - Lod is based on area
length_lod = determinant / length_major;
}
aniso_ratio = min(length_major / length_minor, PS_ANISOTROPIC_FILTERING);
length_lod = length_major / aniso_ratio;
// clamp to top Lod
if (length_lod < 1.0f)
aniso_ratio = max(1.0f, aniso_ratio * length_lod);
aniso_ratio = round(aniso_ratio);
aniso_line = aniso_line_dir * 0.5f * length_major * (1.0f / sz);
aniso_line = aniso_line_dir * 0.5f * (1.0f / sz);
}
#if PS_AUTOMATIC_LOD == 1
float lod = log2(length_lod);
#elif PS_MANUAL_LOD == 1
float lod = manual_lod(uv_w);
#else
float lod = 0; // No Lod
float lod = 0.0f; // No Lod
#endif
float4 colour;
if (aniso_ratio == 1.0f)
colour = Texture.SampleLevel(TextureSampler, uv, lod);
else
{
float4 num = float4(0, 0, 0, 0);
for (int i = 0; i < aniso_ratio; i++)
{
float2 d = -aniso_line + (0.5f + i) * (2.0f * aniso_line) / aniso_ratio;
float4 num = float4(0.0f, 0.0f, 0.0f, 0.0f);
float2 segment = (2.0f * aniso_line) / aniso_ratio;
int aniso_ratio_i = (int)aniso_ratio;
for (int i = 0; i < aniso_ratio_i; i++)
{
float2 d = -aniso_line + (0.5f + i) * segment;
float2 uv_sample = uv + d;
float4 sample_colour = Texture.SampleLevel(TextureSampler, uv_sample, lod);
num += sample_colour;
@@ -407,7 +478,7 @@ float4 sample_c_af(float2 uv, float uv_w)
float4 sample_c(float2 uv, float uv_w, int2 xy)
{
#if PS_TEX_IS_FB == 1
return RtTexture.Load(int3(int2(xy), 0));
return RtLoad(xy);
#elif PS_REGION_RECT == 1
return Texture.Load(int3(int2(uv), 0));
#else
@@ -602,7 +673,7 @@ float4x4 sample_4p(uint4 u)
uint fetch_raw_depth(int2 xy)
{
#if PS_TEX_IS_FB == 1
float4 col = RtTexture.Load(int3(xy, 0));
float4 col = RtLoad(xy);
#else
float4 col = Texture.Load(int3(xy, 0));
#endif
@@ -612,7 +683,7 @@ uint fetch_raw_depth(int2 xy)
float4 fetch_raw_color(int2 xy)
{
#if PS_TEX_IS_FB == 1
return RtTexture.Load(int3(xy, 0));
return RtLoad(xy);
#else
return Texture.Load(int3(xy, 0));
#endif
@@ -621,7 +692,7 @@ float4 fetch_raw_color(int2 xy)
float4 fetch_c(int2 uv)
{
#if PS_TEX_IS_FB == 1
return RtTexture.Load(int3(uv, 0));
return RtLoad(uv);
#else
return Texture.Load(int3(uv, 0));
#endif
@@ -707,7 +778,7 @@ float4 sample_depth(float2 st, float2 pos)
}
else if (PS_DEPTH_FMT == 1)
{
// Based on ps_convert_float32_rgba8 of convert
// Based on ps_convert_depth32_rgba8 of convert
// Convert a FLOAT32 depth texture into a RGBA color texture
uint d = uint(fetch_c(uv).r * exp2(32.0f));
@@ -715,7 +786,7 @@ float4 sample_depth(float2 st, float2 pos)
}
else if (PS_DEPTH_FMT == 2)
{
// Based on ps_convert_float16_rgb5a1 of convert
// Based on ps_convert_depth16_rgb5a1 of convert
// Convert a FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
uint d = uint(fetch_c(uv).r * exp2(32.0f));
@@ -1027,7 +1098,7 @@ void ps_fbmask(inout float4 C, float2 pos_xy)
if (PS_FBMASK)
{
float multi = PS_COLCLIP_HW ? 65535.0f : 255.0f;
float4 RT = trunc(RtTexture.Load(int3(pos_xy, 0)) * multi + 0.1f);
float4 RT = trunc(RtLoad(int2(pos_xy)) * multi + 0.1f);
C = (float4)(((uint4)C & ~FbMask) | ((uint4)RT & FbMask));
}
}
@@ -1103,7 +1174,7 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
As_rgba.rgb = (float3)1.0f;
}
float4 RT = SW_BLEND_NEEDS_RT ? RtTexture.Load(int3(pos_xy, 0)) : (float4)0.0f;
float4 RT = SW_BLEND_NEEDS_RT ? RtLoad(int2(pos_xy)) : (float4)0.0f;
if (PS_SHUFFLE && SW_BLEND_NEEDS_RT)
{
@@ -1236,24 +1307,63 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
}
}
#if PS_ROV_EARLYDEPTHSTENCIL
[earlydepthstencil]
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
#define DISCARD { rov_discard_color = true; rov_discard_depth = true; }
#define DISCARD_COLOR rov_discard_color = true
#define DISCARD_DEPTH rov_discard_depth = true
#else
#define DISCARD discard
#define DISCARD_COLOR o_col0 = RtLoad(input.p.xy)
#define DISCARD_DEPTH input.p.z = DepthLoad(input.p.xy)
#endif
#if (PS_RETURN_COLOR || PS_RETURN_DEPTH)
PS_OUTPUT ps_main(PS_INPUT input)
#else
void ps_main(PS_INPUT input)
#endif
{
// Must floor before depth testing.
#if PS_ZFLOOR
input.p.z = floor(input.p.z * exp2(32.0f)) * exp2(-32.0f);
#endif
#if PS_ZTST == ZTST_GEQUAL
if (input.p.z < DepthTexture.Load(int3(input.p.xy, 0)).r)
discard;
#elif PS_ZTST == ZTST_GREATER
if (input.p.z <= DepthTexture.Load(int3(input.p.xy, 0)).r)
discard;
#if PS_ROV_COLOR
rov_rt_value = RtTextureRov[input.p.xy];
#endif
#if PS_ROV_DEPTH
rov_depth_value = DepthTextureRov[input.p.xy];
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
bool rov_discard_color = false;
bool rov_discard_depth = false;
#endif
// Use ROV discard macro for since we cannot do
// conditional discard based on value read from ROV.
#if PS_ZTST == ZTST_GEQUAL
if (input.p.z < DepthLoad(input.p.xy))
DISCARD;
#elif PS_ZTST == ZTST_GREATER
if (input.p.z <= DepthLoad(input.p.xy))
DISCARD;
#endif
float4 C = ps_color(input);
#if PS_AA1
float cov = clamp(1.0f - abs(input.inv_cov), 0.0f, 1.0f);
#if PS_AA1 == PS_AA1_LINE
// Blur only outer part of the line by scaling coverage.
float cov = clamp(LineCovScale * (1.0f - abs(input.inv_cov)), 0.0f, 1.0f);
#else
float cov = clamp(1.0f - abs(input.inv_cov), 0.0f, 1.0f);
#endif
#if PS_ABE
if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.0f * cov;
@@ -1267,13 +1377,11 @@ PS_OUTPUT ps_main(PS_INPUT input)
bool atst_pass = atst(C);
#if PS_AFAIL == AFAIL_KEEP
#if PS_ATST != PS_ATST_NONE && PS_AFAIL == AFAIL_KEEP
if (!atst_pass)
discard;
#endif
PS_OUTPUT output;
if (PS_SCANMSK & 2)
{
// fail depth test on prohibited lines
@@ -1284,7 +1392,7 @@ PS_OUTPUT ps_main(PS_INPUT input)
float4 alpha_blend = (float4)0.0f;
if (SW_AD_TO_HW)
{
float4 RT = PS_RTA_CORRECTION ? trunc(RtTexture.Load(int3(input.p.xy, 0)) * 128.0f + 0.1f) : trunc(RtTexture.Load(int3(input.p.xy, 0)) * 255.0f + 0.1f);
float4 RT = PS_RTA_CORRECTION ? trunc(RtLoad(input.p.xy) * 128.0f + 0.1f) : trunc(RtLoad(input.p.xy) * 255.0f + 0.1f);
alpha_blend = (float4)(RT.a / 128.0f);
}
else
@@ -1308,9 +1416,9 @@ PS_OUTPUT ps_main(PS_INPUT input)
#if PS_WRITE_RG == 1
// Pseudo 16 bits access.
float rt_a = RtTexture.Load(int3(input.p.xy, 0)).g;
float rt_a = RtLoad(input.p.xy).g;
#else
float rt_a = RtTexture.Load(int3(input.p.xy, 0)).a;
float rt_a = RtLoad(input.p.xy).a;
#endif
#if (PS_DATE & 3) == 1
@@ -1329,9 +1437,8 @@ PS_OUTPUT ps_main(PS_INPUT input)
#endif
#endif
if (bad)
discard;
if (bad)
discard;
#endif
#if PS_DATE == 3
@@ -1342,17 +1449,29 @@ PS_OUTPUT ps_main(PS_INPUT input)
discard;
#endif
// Output values
#if !PS_NO_COLOR
#if PS_DATE == 1 || PS_DATE == 2
float o_col0;
#else
float4 o_col0;
#if !PS_NO_COLOR1
float4 o_col1;
#endif
#endif
#endif
// Get first primitive that will write a failling alpha value
#if PS_DATE == 1
// DATM == 0
// Pixel with alpha equal to 1 will failed (128-255)
output.c = (C.a > 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
o_col0 = (C.a > 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
#elif PS_DATE == 2
// DATM == 1
// Pixel with alpha equal to 0 will failed (0-127)
output.c = (C.a < 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
o_col0 = (C.a < 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
#else
// Not primid DATE setup
@@ -1427,32 +1546,32 @@ PS_OUTPUT ps_main(PS_INPUT input)
alpha_blend.a = float(atst_pass);
#endif
// Output color scaling
#if !PS_NO_COLOR
output.c0.a = PS_RTA_CORRECTION ? C.a / 128.0f : C.a / 255.0f;
output.c0.rgb = PS_COLCLIP_HW ? float3(C.rgb / 65535.0f) : C.rgb / 255.0f;
o_col0.a = PS_RTA_CORRECTION ? C.a / 128.0f : C.a / 255.0f;
o_col0.rgb = PS_COLCLIP_HW ? float3(C.rgb / 65535.0f) : C.rgb / 255.0f;
#if !PS_NO_COLOR1
output.c1 = alpha_blend;
o_col1 = alpha_blend;
#endif
#endif // !PS_NO_COLOR
// Alpha test with feedback
#if PS_AFAIL == AFAIL_FB_ONLY
if (!atst_pass)
input.p.z = DepthTexture.Load(int3(input.p.xy, 0)).r;
DISCARD_DEPTH;
#elif PS_AFAIL == AFAIL_ZB_ONLY
if (!atst_pass)
output.c0 = RtTexture.Load(int3(input.p.xy, 0));
DISCARD_COLOR;
#elif PS_AFAIL == AFAIL_RGB_ONLY || PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
if (!atst_pass)
{
output.c0.a = RtTexture.Load(int3(input.p.xy, 0)).a;
o_col0.a = RtLoad(input.p.xy).a; // discard alpha
#if PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
input.p.z = DepthTexture.Load(int3(input.p.xy, 0)).r;
DISCARD_DEPTH;
#endif
}
#endif
#endif // !PS_NO_COLOR
#endif // PS_DATE != 1/2
#if PS_ZCLAMP
@@ -1461,18 +1580,40 @@ PS_OUTPUT ps_main(PS_INPUT input)
#if PS_AA1 == PS_AA1_TRIANGLE_SW_Z
if (!bool(input.interior))
input.p.z = DepthTexture.Load(int3(input.p.xy, 0)).r; // No depth update for triangle edges.
DISCARD_DEPTH; // No depth update for triangle edges.
#endif
#if ZWRITE
#if SW_DEPTH && PS_NO_COLOR1 && DX12
// Output color clone for feedback as well as real depth.
output.depth_color = input.p.z;
#if (PS_RETURN_COLOR || PS_RETURN_DEPTH)
PS_OUTPUT output;
#endif
// Color write back
#if PS_RETURN_COLOR
output.c0 = o_col0;
#if !PS_NO_COLOR1
output.c1 = o_col1;
#endif
#elif PS_RETURN_COLOR_ROV
o_col0 = (FbMask == 0xFFu) ? RtLoad(input.p.xy) : o_col0; // channel masking
if (!rov_discard_color)
RtWrite(input.p.xy, o_col0);
#endif
// Depth write back
#if PS_RETURN_DEPTH
output.depth = input.p.z;
#if SW_DEPTH && PS_NO_COLOR1 && PS_DEPTH_FEEDBACK_SUPPORT == 2
// Output color clone for feedback.
output.depth_color = input.p.z;
#endif
#elif PS_RETURN_DEPTH_ROV
if (!rov_discard_depth)
DepthWrite(input.p.xy, input.p.z);
#endif
#if (PS_RETURN_COLOR || PS_RETURN_DEPTH)
return output;
#endif
}
#endif // PIXEL_SHADER
@@ -1495,7 +1636,7 @@ cbuffer cb0
float2 TextureOffset;
float2 PointSize;
uint MaxDepth;
uint _cb0_pad0;
float LineAA1Width;
};
#ifdef DX12
@@ -1738,11 +1879,9 @@ VS_OUTPUT vs_main_expand(uint vid : SV_VertexID)
// Use bottom minus top for delta regardless of which vertex we are expanding.
float2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy);
float2 line_vector = normalize(line_delta / VertexScale);
#if VS_EXPAND == VS_EXPAND_LINE
float2 line_expand = float2(line_vector.y, -line_vector.x);
#elif VS_EXPAND == VS_EXPAND_LINE_AA1
// Expand in y direction for shallow lines and x direction for steep lines.
float2 line_expand = abs(line_vector.x) >= abs(line_vector.y) ? float2(0.0f, 2.0f) : float2(2.0f, 0.0f);
#if VS_EXPAND == VS_EXPAND_LINE_AA1
line_expand *= 2.0f * LineAA1Width;
#endif
float2 line_width = (line_expand * PointSize) / 2;
float2 offset = is_right ? line_width : -line_width;
@@ -1875,11 +2014,6 @@ VS_OUTPUT vs_main_expand(uint vid : SV_VertexID)
vtx.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none.
vtx.interior = 0;
#if !VS_IIP
// Get the provoking vertex color (first vertex in DX)
vtx.c = i0 == 0 ? vtx.c : (i1 == 0 ? other.c : opposite.c);
#endif
}
return vtx;
+166 -159
View File
@@ -3,21 +3,12 @@
//#version 420 // Keep it for editor detection
#ifdef VERTEX_SHADER
layout(location = 0) in vec2 POSITION;
layout(location = 1) in vec2 TEXCOORD0;
layout(location = 7) in vec4 COLOR;
// FIXME set the interpolation (don't know what dx do)
// flat means that there is no interpolation. The value given to the fragment shader is based on the provoking vertex conventions.
//
// noperspective means that there will be linear interpolation in window-space. This is usually not what you want, but it can have its uses.
//
// smooth, the default, means to do perspective-correct interpolation.
//
// The centroid qualifier only matters when multisampling. If this qualifier is not present, then the value is interpolated to the pixel's center, anywhere in the pixel, or to one of the pixel's samples. This sample may lie outside of the actual primitive being rendered, since a primitive can cover only part of a pixel's area. The centroid qualifier is used to prevent this; the interpolation point must fall within both the pixel's area and the primitive's area.
out vec4 PSin_p;
out vec2 PSin_t;
out vec4 PSin_c;
@@ -40,44 +31,125 @@ in vec4 PSin_c;
layout(binding = 0) uniform sampler2D TextureSampler;
// Give a different name so I remember there is a special case!
#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits)
layout(location = 0) out uint SV_Target1;
#elif defined(ps_convert_float32_depth_to_color)
layout(location = 0) out float SV_Target0;
#elif !defined(ps_datm1) && \
!defined(ps_datm0) && \
!defined(ps_datm1_rta_correction) && \
!defined(ps_datm0_rta_correction) && \
!defined(ps_convert_rgba8_float32) && \
!defined(ps_convert_rgba8_float24) && \
!defined(ps_convert_rgba8_float16) && \
!defined(ps_convert_rgb5a1_float16) && \
!defined(ps_convert_rgba8_float32_biln) && \
!defined(ps_convert_rgba8_float24_biln) && \
!defined(ps_convert_rgba8_float16_biln) && \
!defined(ps_convert_rgb5a1_float16_biln) && \
!defined(ps_convert_float32_float24) && \
!defined(ps_depth_copy)
layout(location = 0) out vec4 SV_Target0;
#if HAS_INTEGER_OUTPUT
layout(location = 0) out uint o_col0;
#define OUTPUT o_col0
#elif HAS_DEPTH_OUTPUT
out float gl_FragDepth;
#define OUTPUT gl_FragDepth
#elif HAS_FLOAT32_OUTPUT
layout(location = 0) out float o_col0;
#define OUTPUT o_col0
#elif HAS_STENCIL_OUTPUT
#else
layout(location = 0) out vec4 o_col0;
#define OUTPUT o_col0
#endif
#if HAS_FLOAT32_INPUT
float sample_c()
{
return texture(TextureSampler, PSin_t).r;
}
#else
vec4 sample_c()
{
return texture(TextureSampler, PSin_t);
}
#endif
uint rgba8_to_uint(vec4 c)
{
uvec4 i = uvec4(c * 255.5f) & 0xFFu;
return i.r | (i.g << 8) | (i.b << 16) | (i.a << 24);
}
uint rgb5a1_to_uint(vec4 c)
{
uvec4 i = uvec4(c * 255.5f) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u);
return (i.r >> 3) | (i.g << 2) | (i.b << 7) | (i.a << 8);
}
uint depth_to_uint(float d)
{
return uint(d * exp2(32.0f));
}
vec4 uint_to_rgba8(uint i)
{
return vec4((i & 0xFFu), ((i >> 8) & 0xFFu), ((i >> 16) & 0xFFu), ((i >> 24) & 0xFFu)) / 255.0f;
}
vec4 uint_to_rgb5a1(uint i)
{
return vec4(uvec4(i << 3, i >> 2, i >> 7, i >> 8) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u)) / 255.0f;
}
float uint_to_depth32(uint i)
{
return float(i) * exp2(-32.0f);
}
float uint_to_depth24(uint i)
{
return float(i & 0xFFFFFFu) * exp2(-32.0f);
}
float uint_to_depth16(uint i)
{
return float(i & 0xFFFFu) * exp2(-32.0f);
}
float rgba8_to_depth32(vec4 val)
{
return uint_to_depth32(rgba8_to_uint(val));
}
float rgba8_to_depth24(vec4 val)
{
return uint_to_depth24(rgba8_to_uint(val));
}
float rgba8_to_depth16(vec4 val)
{
return uint_to_depth16(rgba8_to_uint(val));
}
float rgb5a1_to_depth16(vec4 val)
{
return uint_to_depth16(rgb5a1_to_uint(val));
}
vec4 depth32_to_rgba8(float d)
{
return uint_to_rgba8(depth_to_uint(d));
}
vec4 depth16_to_rgb5a1(float d)
{
return uint_to_rgb5a1(depth_to_uint(d));
}
float depth32_to_depth24(float d)
{
return uint_to_depth24(depth_to_uint(d));
}
#ifdef ps_copy
void ps_copy()
{
SV_Target0 = sample_c();
OUTPUT = sample_c();
}
#endif
#ifdef ps_depth_copy
void ps_depth_copy()
{
gl_FragDepth = sample_c().r;
OUTPUT = sample_c();
}
#endif
@@ -96,126 +168,47 @@ void ps_downsample_copy()
for (int xoff = 0; xoff < DownsampleFactor; xoff++)
result += texelFetch(TextureSampler, coord + ivec2(xoff * StepMultiplier, yoff * StepMultiplier), 0);
}
SV_Target0 = result / Weight;
o_col0 = result / Weight;
}
#endif
#ifdef ps_convert_rgba8_16bits
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
void ps_convert_rgba8_16bits()
#ifdef ps_convert_rgb5a1_16bits
void ps_convert_rgb5a1_16bits()
{
highp uvec4 i = uvec4(sample_c() * vec4(255.5f, 255.5f, 255.5f, 255.5f));
SV_Target1 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
OUTPUT = rgb5a1_to_uint(sample_c());
}
#endif
#ifdef ps_convert_float32_32bits
void ps_convert_float32_32bits()
#ifdef ps_convert_depth32_32bits
void ps_convert_depth32_32bits()
{
// Convert a GL_FLOAT32 depth texture into a 32 bits UINT texture
SV_Target1 = uint(exp2(32.0f) * sample_c().r);
OUTPUT = depth_to_uint(sample_c());
}
#endif
#ifdef ps_convert_float32_rgba8
void ps_convert_float32_rgba8()
#ifdef ps_convert_depth32_rgba8
void ps_convert_depth32_rgba8()
{
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
uint d = uint(sample_c().r * exp2(32.0f));
SV_Target0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0);
OUTPUT = depth32_to_rgba8(sample_c());
}
#endif
#ifdef ps_convert_float16_rgb5a1
void ps_convert_float16_rgb5a1()
#ifdef ps_convert_depth16_rgb5a1
void ps_convert_depth16_rgb5a1()
{
// Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
uint d = uint(sample_c().r * exp2(32.0f));
SV_Target0 = vec4(uvec4(d << 3, d >> 2, d >> 7, d >> 8) & uvec4(0xf8, 0xf8, 0xf8, 0x80)) / 255.0f;
OUTPUT = depth16_to_rgb5a1(sample_c());
}
#endif
float rgba8_to_depth32(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
}
float rgba8_to_depth24(vec4 unorm)
{
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
}
float rgba8_to_depth16(vec4 unorm)
{
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
return float(c.r | (c.g << 8)) * exp2(-32.0f);
}
float rgb5a1_to_depth16(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
}
#ifdef ps_convert_float32_depth_to_color
void ps_convert_float32_depth_to_color()
{
SV_Target0 = sample_c().r;
}
#endif
#ifdef ps_convert_float32_color_to_depth
void ps_convert_float32_color_to_depth()
{
gl_FragDepth = sample_c().r;
}
#endif
#ifdef ps_convert_float32_float24
void ps_convert_float32_float24()
#ifdef ps_convert_depth32_depth24
void ps_convert_depth32_depth24()
{
// Truncates depth value to 24bits
uint d = uint(sample_c().r * exp2(32.0f)) & 0xFFFFFFu;
gl_FragDepth = float(d) * exp2(-32.0f);
}
#endif
#ifdef ps_convert_rgba8_float32
void ps_convert_rgba8_float32()
{
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth32(sample_c());
}
#endif
#ifdef ps_convert_rgba8_float24
void ps_convert_rgba8_float24()
{
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth24(sample_c());
}
#endif
#ifdef ps_convert_rgba8_float16
void ps_convert_rgba8_float16()
{
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth16(sample_c());
}
#endif
#ifdef ps_convert_rgb5a1_float16
void ps_convert_rgb5a1_float16()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
gl_FragDepth = rgb5a1_to_depth16(sample_c());
OUTPUT = depth32_to_depth24(sample_c());
}
#endif
@@ -229,41 +222,55 @@ void ps_convert_rgb5a1_float16()
float depthTR = CONVERT_FN(texelFetch(TextureSampler, coords.zy, 0)); \
float depthBL = CONVERT_FN(texelFetch(TextureSampler, coords.xw, 0)); \
float depthBR = CONVERT_FN(texelFetch(TextureSampler, coords.zw, 0)); \
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
OUTPUT = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
#ifdef ps_convert_rgba8_float32_biln
void ps_convert_rgba8_float32_biln()
#ifdef ps_convert_rgba8_depth32
void ps_convert_rgba8_depth32()
{
// Convert an RGBA texture into a float depth texture
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
#else
OUTPUT = rgba8_to_depth32(sample_c());
#endif
}
#endif
#ifdef ps_convert_rgba8_float24_biln
void ps_convert_rgba8_float24_biln()
#ifdef ps_convert_rgba8_depth24
void ps_convert_rgba8_depth24()
{
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
#else
OUTPUT = rgba8_to_depth24(sample_c());
#endif
}
#endif
#ifdef ps_convert_rgba8_float16_biln
void ps_convert_rgba8_float16_biln()
#ifdef ps_convert_rgba8_depth16
void ps_convert_rgba8_depth16()
{
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
#else
OUTPUT = rgba8_to_depth16(sample_c());
#endif
}
#endif
#ifdef ps_convert_rgb5a1_float16_biln
void ps_convert_rgb5a1_float16_biln()
#ifdef ps_convert_rgb5a1_depth16
void ps_convert_rgb5a1_depth16()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
#else
OUTPUT = rgb5a1_to_depth16(sample_c());
#endif
}
#endif
@@ -373,7 +380,7 @@ void ps_convert_rgb5a1_8i()
uint red = (denorm_c.r >> 3) & 0x1Fu;
uint green = (denorm_c.g >> 3) & 0x1Fu;
SV_Target0 = vec4(float(((green << 5) | red) & 0xFFu) / 255.0f);
o_col0 = vec4(float(((green << 5) | red) & 0xFFu) / 255.0f);
}
else
{
@@ -381,7 +388,7 @@ void ps_convert_rgb5a1_8i()
uint blue = (denorm_c.b >> 3) & 0x1Fu;
uint alpha = denorm_c.a & 0x80u;
SV_Target0 = vec4(float((alpha | (blue << 2) | (green >> 3)) & 0xFFu) / 255.0f);
o_col0 = vec4(float((alpha | (blue << 2) | (green >> 3)) & 0xFFu) / 255.0f);
}
}
#endif
@@ -430,7 +437,7 @@ void ps_convert_rgba_8i()
vec4 pixel = texelFetch(TextureSampler, ivec2(coord), 0);
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
SV_Target0 = vec4(sel1);
o_col0 = vec4(sel1);
}
#endif
@@ -438,7 +445,7 @@ void ps_convert_rgba_8i()
void ps_filter_transparency()
{
vec4 c = sample_c();
SV_Target0 = vec4(c.rgb, 1.0);
o_col0 = vec4(c.rgb, 1.0);
}
#endif
@@ -486,7 +493,7 @@ void ps_datm0_rta_correction()
void ps_rta_correction()
{
vec4 value = sample_c();
SV_Target0 = vec4(value.rgb, value.a / (128.25f / 255.0f));
o_col0 = vec4(value.rgb, value.a / (128.25f / 255.0f));
}
#endif
@@ -494,7 +501,7 @@ void ps_rta_correction()
void ps_rta_decorrection()
{
vec4 value = sample_c();
SV_Target0 = vec4(value.rgb, value.a * (128.25f / 255.0f));
o_col0 = vec4(value.rgb, value.a * (128.25f / 255.0f));
}
#endif
@@ -502,7 +509,7 @@ void ps_rta_decorrection()
void ps_colclip_init()
{
vec4 value = sample_c();
SV_Target0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a);
o_col0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a);
}
#endif
@@ -510,7 +517,7 @@ void ps_colclip_init()
void ps_colclip_resolve()
{
vec4 value = sample_c();
SV_Target0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a);
o_col0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a);
}
#endif
@@ -525,7 +532,7 @@ void ps_convert_clut_4()
uvec2 pos = uvec2(index % 8u, index / 8u);
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * vec2(scale)));
SV_Target0 = texelFetch(TextureSampler, final, 0);
o_col0 = texelFetch(TextureSampler, final, 0);
}
#endif
@@ -545,7 +552,7 @@ void ps_convert_clut_8()
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * vec2(scale)));
SV_Target0 = texelFetch(TextureSampler, final, 0);
o_col0 = texelFetch(TextureSampler, final, 0);
}
#endif
@@ -600,31 +607,31 @@ void ps_yuv()
break;
}
SV_Target0 = o;
o_col0 = o;
}
#endif
#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1) || defined(ps_stencil_image_init_2) || defined(ps_stencil_image_init_3)
#if defined(ps_primid_image_init_0) || defined(ps_primid_image_init_1) || defined(ps_primid_image_init_2) || defined(ps_primid_image_init_3)
void main()
{
SV_Target0 = vec4(0x7FFFFFFF);
o_col0 = vec4(0x7FFFFFFF);
#ifdef ps_stencil_image_init_0
#ifdef ps_primid_image_init_0
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
SV_Target0 = vec4(-1);
o_col0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_1
#ifdef ps_primid_image_init_1
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
SV_Target0 = vec4(-1);
o_col0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_2
#ifdef ps_primid_image_init_2
if((254.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
SV_Target0 = vec4(-1);
o_col0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_3
#ifdef ps_primid_image_init_3
if(sample_c().a < (254.5f / 255.0f)) // >= 0x80 pass
SV_Target0 = vec4(-1);
o_col0 = vec4(-1);
#endif
}
#endif
+86 -75
View File
@@ -59,7 +59,7 @@
#define NEEDS_DEPTH_FOR_ZTST (PS_ZTST == ZTST_GEQUAL || PS_ZTST == ZTST_GREATER)
#define NEEDS_DEPTH_FOR_AA1 (PS_AA1 == PS_AA1_TRIANGLE_SW_Z)
#define NEEDS_RT (NEEDS_RT_EARLY || NEEDS_RT_FOR_AFAIL || (!PS_PRIMID_INIT && (PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW)) || PS_COLOR_FEEDBACK)
#define NEEDS_RT (NEEDS_RT_EARLY || NEEDS_RT_FOR_AFAIL || (!PS_PRIMID_INIT && (PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW)))
#define NEEDS_TEX (PS_TFX != 4)
#define SW_DEPTH (NEEDS_DEPTH_FOR_AFAIL || NEEDS_DEPTH_FOR_ZTST || NEEDS_DEPTH_FOR_AA1)
#define ZWRITE (SW_DEPTH || PS_ZCLAMP || PS_ZFLOOR)
@@ -93,6 +93,13 @@ layout(std140, binding = 0) uniform cb21
float ScaledScaleFactor;
float RcpScaleFactor;
float _pad0_cb1;
float _pad1_cb1;
float LineCovScale;
float _pad2_cb1;
float _pad3_cb1;
float _pad4_cb1;
};
in SHADER
@@ -121,7 +128,7 @@ in SHADER
#if defined(GL_EXT_shader_framebuffer_fetch)
#undef TARGET_0_QUALIFIER
#define TARGET_0_QUALIFIER inout
#define LAST_FRAG_COLOR SV_Target0
#define LAST_FRAG_COLOR o_col0
#elif defined(GL_ARM_shader_framebuffer_fetch)
#define LAST_FRAG_COLOR gl_LastFragColorARM
#endif
@@ -129,20 +136,20 @@ in SHADER
#if !PS_NO_COLOR && !PS_NO_COLOR1
// Same buffer but 2 colors for dual source blending
layout(location = 0, index = 0) TARGET_0_QUALIFIER vec4 SV_Target0;
layout(location = 0, index = 1) out vec4 SV_Target1;
layout(location = 0, index = 0) TARGET_0_QUALIFIER vec4 o_col0;
layout(location = 0, index = 1) out vec4 o_col1;
#elif !PS_NO_COLOR
layout(location = 0) TARGET_0_QUALIFIER vec4 SV_Target0;
layout(location = 0) TARGET_0_QUALIFIER vec4 o_col0;
#endif
// Depth feedback mode 2 is for depth as color.
// Use FB fetch for the feedback if it's available.
#if SW_DEPTH && PS_NO_COLOR1 && (DEPTH_FEEDBACK_SUPPORT == 2)
#if HAS_FRAMEBUFFER_FETCH
layout(location = 1) inout float SV_Target1;
#else
layout(location = 1) out float SV_Target1;
#endif
#if HAS_FRAMEBUFFER_FETCH
layout(location = 1) inout float o_col1;
#else
layout(location = 1) out float o_col1;
#endif
#endif
#if NEEDS_TEX
@@ -180,14 +187,14 @@ vec4 sample_from_rt()
#endif
}
vec4 sample_from_depth()
float sample_from_depth()
{
#if !SW_DEPTH
return vec4(0.0);
return 0.0f;
#elif HAS_FRAMEBUFFER_FETCH && (DEPTH_FEEDBACK_SUPPORT == 2)
return SV_Target1;
return o_col1;
#else
return texelFetch(DepthSampler, ivec2(gl_FragCoord.xy), 0);
return texelFetch(DepthSampler, ivec2(gl_FragCoord.xy), 0).r;
#endif
}
@@ -213,22 +220,27 @@ float manual_lod(float uv_w)
vec4 sample_c_af(vec2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = (any(isnan(uv)) || any(isinf(uv))) ? vec2(0, 0) : uv;
uv = (any(isnan(uv)) || any(isinf(uv))) ? vec2(0.0f, 0.0f) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// And https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_filter_anisotropic.txt
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
vec2 sz = textureSize(TextureSampler, 0);
vec2 dX = dFdx(uv) * sz;
vec2 dY = dFdy(uv) * sz;
float length_x = length(dX);
float length_y = length(dY);
// Calculate Ellipse Transform
bool d_zero = length(dX) == 0 || length(dY) == 0;
bool d_par = (dX.x * dY.y - dY.x * dX.y) == 0;
bool d_per = dot(dX, dY) == 0;
bool d_zero = length_x < 0.001f || length_y < 0.001f;
float f = (dX.x * dY.y - dX.y * dY.x);
bool d_par = f < 0.001f;
bool d_per = dot(dX, dY) < 0.001f;
bool d_inf_nan = any(isinf(dX)) || any(isinf(dY)) || any(isnan(dX)) || any(isnan(dY));
if (!(d_zero || d_par || d_per || d_inf_nan))
@@ -236,38 +248,46 @@ vec4 sample_c_af(vec2 uv, float uv_w)
float A = dX.y * dX.y + dY.y * dY.y;
float B = -2 * (dX.x * dX.y + dY.x * dY.y);
float C = dX.x * dX.x + dY.x * dY.x;
float f = (dX.x * dY.y - dY.x * dX.y);
float F = f * f;
float p = A - C;
float q = A + C;
float t = sqrt(p * p + B * B);
float signB = sign(B);
float denom_plus = t * (q + t);
float denom_minus = t * (q - t);
float sqrtA = sqrt(F * (t + p));
float sqrtB = sqrt(F * (t - p));
float inv_sqrt_denom_plus = inversesqrt(denom_plus);
float inv_sqrt_denom_minus = inversesqrt(denom_minus);
vec2 new_dX = vec2(
sqrt(F * (t + p) / (t * (q + t))),
sqrt(F * (t - p) / (t * (q + t))) * sign(B)
sqrtA * inv_sqrt_denom_plus,
sqrtB * inv_sqrt_denom_plus * signB
);
vec2 new_dY = vec2(
sqrt(F * (t - p) / (t * (q - t))) * -sign(B),
sqrt(F * (t + p) / (t * (q - t)))
sqrtB * inv_sqrt_denom_minus * -signB,
sqrtA * inv_sqrt_denom_minus
);
d_inf_nan = any(isinf(new_dX)) || any(isinf(new_dY)) || any(isnan(new_dX)) || any(isnan(new_dY));
if (!d_inf_nan)
{
dX = new_dX;
dY = new_dY;
length_x = length(dX);
length_y = length(dY);
}
}
// Compute AF values
float squared_length_x = dX.x * dX.x + dX.y * dX.y;
float squared_length_y = dY.x * dY.x + dY.y * dY.y;
float determinant = abs(dX.x * dY.y - dX.y * dY.x);
bool is_major_x = squared_length_x > squared_length_y;
float squared_length_major = is_major_x ? squared_length_x : squared_length_y;
float length_major = sqrt(squared_length_major);
bool is_major_x = length_x > length_y;
float length_major = is_major_x ? length_x : length_y;
float length_minor = is_major_x ? length_y : length_x;
float aniso_ratio;
float length_lod;
@@ -279,57 +299,42 @@ vec4 sample_c_af(vec2 uv, float uv_w)
// Perform isotropic filtering instead.
aniso_ratio = 1.0f;
length_lod = length_major;
aniso_line = vec2(0, 0);
aniso_line = vec2(0.0f, 0.0f);
}
else
{
float norm_major = 1.0f / length_major;
vec2 aniso_line_dir = vec2(
(is_major_x ? dX.x : dY.x) * norm_major,
(is_major_x ? dX.y : dY.y) * norm_major
);
aniso_ratio = squared_length_major / determinant;
vec2 aniso_line_dir = is_major_x ? dX : dY;
// Calculate the minor length of the ellipse for Lod, while also clamping the ratio of anisotropy.
if (aniso_ratio > PS_ANISOTROPIC_FILTERING)
{
// ratio is clamped - Lod is based on ratio (preserves area)
aniso_ratio = PS_ANISOTROPIC_FILTERING;
length_lod = length_major / PS_ANISOTROPIC_FILTERING;
}
else
{
// ratio not clamped - Lod is based on area
length_lod = determinant / length_major;
}
aniso_ratio = min(length_major / length_minor, PS_ANISOTROPIC_FILTERING);
length_lod = length_major / aniso_ratio;
// clamp to top Lod
if (length_lod < 1.0f)
aniso_ratio = max(1.0f, aniso_ratio * length_lod);
aniso_ratio = round(aniso_ratio);
aniso_line = aniso_line_dir * 0.5f * length_major * (1.0f / sz);
aniso_line = aniso_line_dir * 0.5f * (1.0f / sz);
}
#if PS_AUTOMATIC_LOD == 1
float lod = log2(length_lod);
#elif PS_MANUAL_LOD == 1
float lod = manual_lod(uv_w);
#else
float lod = 0; // No Lod
float lod = 0.0f; // No Lod
#endif
vec4 colour;
if (aniso_ratio == 1.0f)
colour = textureLod(TextureSampler, uv, lod);
else
{
vec4 num = vec4(0, 0, 0, 0);
vec4 num = vec4(0.0f, 0.0f, 0.0f, 0.0f);
vec2 segment = (2.0f * aniso_line) / aniso_ratio;
for (int i = 0; i < aniso_ratio; i++)
{
vec2 d = -aniso_line + (0.5f + i) * (2.0f * aniso_line) / aniso_ratio;
{
vec2 d = -aniso_line + (0.5f + i) * segment;
vec2 uv_sample = uv + d;
vec4 sample_colour = textureLod(TextureSampler, uv_sample, lod);
num += sample_colour;
@@ -621,13 +626,13 @@ vec4 sample_depth(vec2 st)
#elif PS_DEPTH_FMT == 1
// Based on ps_convert_float32_rgba8 of convert
// Based on ps_convert_depth32_rgba8 of convert
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
uint d = uint(fetch_c(uv).r * exp2(32.0f));
t = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24)));
#elif PS_DEPTH_FMT == 2
// Based on ps_convert_float16_rgb5a1 of convert
// Based on ps_convert_depth16_rgb5a1 of convert
// Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
uint d = uint(fetch_c(uv).r * exp2(32.0f));
t = vec4(uvec4((d & 0x1Fu), ((d >> 5) & 0x1Fu), ((d >> 10) & 0x1Fu), (d >> 15) & 0x01u)) * vec4(8.0f, 8.0f, 8.0f, 128.0f);
@@ -1193,10 +1198,10 @@ void ps_main()
#endif
#if PS_ZTST == ZTST_GEQUAL
if (input_z < sample_from_depth().r)
if (input_z < sample_from_depth())
discard;
#elif PS_ZTST == ZTST_GREATER
if (input_z <= sample_from_depth().r)
if (input_z <= sample_from_depth())
discard;
#endif
@@ -1250,7 +1255,12 @@ void ps_main()
vec4 C = ps_color();
#if PS_AA1
float cov = clamp(1.0f - abs(PSin.inv_cov), 0.0f, 1.0f);
#if PS_AA1 == PS_AA1_LINE
// Blur only outer part of the line by scaling coverage.
float cov = clamp(LineCovScale * (1.0f - abs(PSin.inv_cov)), 0.0f, 1.0f);
#else
float cov = clamp(1.0f - abs(PSin.inv_cov), 0.0f, 1.0f);
#endif
#if PS_ABE
if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.0f * cov;
@@ -1264,7 +1274,7 @@ void ps_main()
bool atst_pass = atst(C);
#if PS_AFAIL == AFAIL_KEEP
#if PS_ATST != PS_ATST_NONE && PS_AFAIL == AFAIL_KEEP
if (!atst_pass)
discard;
#endif
@@ -1293,12 +1303,12 @@ void ps_main()
#if PS_DATE == 1
// DATM == 0
// Pixel with alpha equal to 1 will failed (128-255)
SV_Target0 = (C.a > 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
o_col0 = (C.a > 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
return;
#elif PS_DATE == 2
// DATM == 1
// Pixel with alpha equal to 0 will failed (0-127)
SV_Target0 = (C.a < 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
o_col0 = (C.a < 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
return;
#endif
@@ -1372,7 +1382,7 @@ void ps_main()
// Alpha test with feedback
#if PS_AFAIL == AFAIL_FB_ONLY
if (!atst_pass)
input_z = sample_from_depth().r;
input_z = sample_from_depth();
#elif PS_AFAIL == AFAIL_ZB_ONLY
if (!atst_pass)
C = sample_from_rt();
@@ -1381,17 +1391,17 @@ void ps_main()
{
C.a = sample_from_rt().a;
#if PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
input_z = sample_from_depth().r;
input_z = sample_from_depth();
#endif
}
#endif
// Warning: do not write SV_Target0 until the end since the value might be needed for
// Warning: do not write o_col0 until the end since the value might be needed for
// FB fetch in sample_from_rt().
SV_Target0 = C;
o_col0 = C;
#if !PS_NO_COLOR1
SV_Target1 = alpha_blend;
o_col1 = alpha_blend;
#endif
#endif
@@ -1401,16 +1411,17 @@ void ps_main()
#if PS_AA1 == PS_AA1_TRIANGLE_SW_Z
if (!bool(PSin.interior))
input_z = sample_from_depth().r; // No depth update for triangle edges.
input_z = sample_from_depth(); // No depth update for triangle edges.
#endif
// Writing back depth
#if ZWRITE
#if SW_DEPTH && PS_NO_COLOR1 && (DEPTH_FEEDBACK_SUPPORT == 2)
// Depth as color write. For depth as color feedback we write to both
// color copy and real depth to avoid having to copy back to real depth.
// Warning: do not write SV_Target1 until the end since the value might
// Warning: do not write o_col1 until the end since the value might
// be needed for FB fetch in sample_from_depth().
SV_Target1 = input_z;
o_col1 = input_z;
#endif
// Standard depth write.
gl_FragDepth = input_z;
+18 -12
View File
@@ -12,8 +12,9 @@ layout(std140, binding = 1) uniform cb20
vec2 TextureOffset;
vec2 PointSize;
uint MaxDepth;
uint pad_cb20;
float LineAA1Width;
};
#ifdef VERTEX_SHADER
@@ -83,7 +84,13 @@ void vs_main()
// example: 133.0625 (133 + 1/16) should start from line 134, ceil(133.0625 - 0.05) still above 133
gl_Position.xy = vec2(i_p) - vec2(0.05f, 0.05f);
gl_Position.xy = gl_Position.xy * VertexScale - VertexOffset;
gl_Position.z = float(z) * exp_min32;
#if HAS_CLIP_CONTROL
gl_Position.z = float(z) * exp_min32;
#else
gl_Position.z = (float(z) * exp_min32) * 2.0f - 1.0f;
#endif
gl_Position.w = 1.0f;
texture_coord();
@@ -160,7 +167,13 @@ ProcessedVertex load_vertex(uint index)
uint z = min(i_z, MaxDepth);
vtx.p.xy = vec2(i_p) - vec2(0.05f, 0.05f);
vtx.p.xy = vtx.p.xy * VertexScale - VertexOffset;
vtx.p.z = float(z) * exp_min32;
#if HAS_CLIP_CONTROL
vtx.p.z = float(z) * exp_min32;
#else
vtx.p.z = (float(z) * exp_min32) * 2.0f - 1.0f;
#endif
vtx.p.w = 1.0f;
vec2 uv = vec2(i_uv) - TextureOffset;
@@ -311,11 +324,9 @@ void main()
// Use bottom minus top for delta regardless of which vertex we are expanding.
vec2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy);
vec2 line_vector = normalize(line_delta / VertexScale);
#if VS_EXPAND == VS_EXPAND_LINE
vec2 line_expand = vec2(line_vector.y, -line_vector.x);
#elif VS_EXPAND == VS_EXPAND_LINE_AA1
// Expand in y direction for shallow lines and x direction for steep lines.
vec2 line_expand = abs(line_vector.x) >= abs(line_vector.y) ? vec2(0.0f, 2.0f) : vec2(2.0f, 0.0f);
#if VS_EXPAND == VS_EXPAND_LINE_AA1
line_expand *= 2.0f * LineAA1Width;
#endif
vec2 line_width = (line_expand * PointSize) / 2;
vec2 offset = is_right ? line_width : -line_width;
@@ -444,11 +455,6 @@ void main()
VSout.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none.
VSout.interior = 0;
#if !VS_IIP
// Get the provoking vertex color (last vertex in GL)
vtx.c = i0 == 2 ? vtx.c : (i1 == 2 ? other.c : opposite.c);
#endif
}
#endif
+155 -140
View File
@@ -20,45 +20,127 @@ void main()
layout(location = 0) in vec2 v_tex;
#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits)
layout(location = 0) out uint o_col0;
#elif defined(ps_convert_float32_depth_to_color)
layout(location = 0) out float o_col0;
#elif !defined(ps_datm1) && \
!defined(ps_datm0) && \
!defined(ps_datm1_rta_correction) && \
!defined(ps_datm0_rta_correction) && \
!defined(ps_convert_rgba8_float32) && \
!defined(ps_convert_rgba8_float24) && \
!defined(ps_convert_rgba8_float16) && \
!defined(ps_convert_rgb5a1_float16) && \
!defined(ps_convert_rgba8_float32_biln) && \
!defined(ps_convert_rgba8_float24_biln) && \
!defined(ps_convert_rgba8_float16_biln) && \
!defined(ps_convert_rgb5a1_float16_biln) && \
!defined(ps_convert_float32_float24) && \
!defined(ps_depth_copy)
layout(location = 0) out vec4 o_col0;
#if HAS_INTEGER_OUTPUT
layout(location = 0) out uint o_col0;
#define OUTPUT o_col0
#elif HAS_DEPTH_OUTPUT
out float gl_FragDepth;
#define OUTPUT gl_FragDepth
#elif HAS_FLOAT32_OUTPUT
layout(location = 0) out float o_col0;
#define OUTPUT o_col0
#elif HAS_STENCIL_OUTPUT
#else
layout(location = 0) out vec4 o_col0;
#define OUTPUT o_col0
#endif
layout(set = 0, binding = 0) uniform sampler2D samp0;
#if HAS_FLOAT32_INPUT
float sample_c(vec2 uv)
{
return texture(samp0, uv).r;
}
#else
vec4 sample_c(vec2 uv)
{
return texture(samp0, uv);
}
#endif
uint rgba8_to_uint(vec4 c)
{
uvec4 i = uvec4(c * 255.5f) & 0xFFu;
return i.r | (i.g << 8) | (i.b << 16) | (i.a << 24);
}
uint rgb5a1_to_uint(vec4 c)
{
uvec4 i = uvec4(c * 255.5f) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u);
return (i.r >> 3) | (i.g << 2) | (i.b << 7) | (i.a << 8);
}
uint depth_to_uint(float d)
{
return uint(d * exp2(32.0f));
}
vec4 uint_to_rgba8(uint i)
{
return vec4((i & 0xFFu), ((i >> 8) & 0xFFu), ((i >> 16) & 0xFFu), ((i >> 24) & 0xFFu)) / 255.0f;
}
vec4 uint_to_rgb5a1(uint i)
{
return vec4(uvec4(i << 3, i >> 2, i >> 7, i >> 8) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u)) / 255.0f;
}
float uint_to_depth32(uint i)
{
return float(i) * exp2(-32.0f);
}
float uint_to_depth24(uint i)
{
return float(i & 0xFFFFFFu) * exp2(-32.0f);
}
float uint_to_depth16(uint i)
{
return float(i & 0xFFFFu) * exp2(-32.0f);
}
float rgba8_to_depth32(vec4 val)
{
return uint_to_depth32(rgba8_to_uint(val));
}
float rgba8_to_depth24(vec4 val)
{
return uint_to_depth24(rgba8_to_uint(val));
}
float rgba8_to_depth16(vec4 val)
{
return uint_to_depth16(rgba8_to_uint(val));
}
float rgb5a1_to_depth16(vec4 val)
{
return uint_to_depth16(rgb5a1_to_uint(val));
}
vec4 depth32_to_rgba8(float d)
{
return uint_to_rgba8(depth_to_uint(d));
}
vec4 depth16_to_rgb5a1(float d)
{
return uint_to_rgb5a1(depth_to_uint(d));
}
float depth32_to_depth24(float d)
{
return uint_to_depth24(depth_to_uint(d));
}
#ifdef ps_copy
void ps_copy()
{
o_col0 = sample_c(v_tex);
OUTPUT = sample_c(v_tex);
}
#endif
#ifdef ps_depth_copy
void ps_depth_copy()
{
gl_FragDepth = sample_c(v_tex).r;
OUTPUT = sample_c(v_tex);
}
#endif
@@ -83,7 +165,7 @@ void ps_downsample_copy()
result += texelFetch(samp0, coord + ivec2(xoff * step_multiplier, yoff * step_multiplier), 0);
}
}
o_col0 = result / Weight;
OUTPUT = result / Weight;
}
#endif
@@ -91,17 +173,15 @@ void ps_downsample_copy()
void ps_filter_transparency()
{
vec4 c = sample_c(v_tex);
o_col0 = vec4(c.rgb, 1.0);
OUTPUT = vec4(c.rgb, 1.0);
}
#endif
#ifdef ps_convert_rgba8_16bits
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
void ps_convert_rgba8_16bits()
#ifdef ps_convert_rgb5a1_16bits
void ps_convert_rgb5a1_16bits()
{
uvec4 i = uvec4(sample_c(v_tex) * vec4(255.5f, 255.5f, 255.5f, 255.5f));
o_col0 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
OUTPUT = rgb5a1_to_uint(sample_c(v_tex));
}
#endif
@@ -141,7 +221,7 @@ void ps_datm0_rta_correction()
void ps_rta_correction()
{
vec4 value = sample_c(v_tex);
o_col0 = vec4(value.rgb, value.a / (128.25f / 255.0f));
OUTPUT = vec4(value.rgb, value.a / (128.25f / 255.0f));
}
#endif
@@ -149,7 +229,7 @@ void ps_rta_correction()
void ps_rta_decorrection()
{
vec4 value = sample_c(v_tex);
o_col0 = vec4(value.rgb, value.a * (128.25f / 255.0f));
OUTPUT = vec4(value.rgb, value.a * (128.25f / 255.0f));
}
#endif
@@ -157,7 +237,7 @@ void ps_rta_decorrection()
void ps_colclip_init()
{
vec4 value = sample_c(v_tex);
o_col0 = vec4(roundEven(value.rgb * 255.0f) / 65535.0f, value.a);
OUTPUT = vec4(roundEven(value.rgb * 255.0f) / 65535.0f, value.a);
}
#endif
@@ -165,116 +245,39 @@ void ps_colclip_init()
void ps_colclip_resolve()
{
vec4 value = sample_c(v_tex);
o_col0 = vec4(vec3(uvec3(value.rgb * 65535.5f) & 255u) / 255.0f, value.a);
OUTPUT = vec4(vec3(uvec3(value.rgb * 65535.5f) & 255u) / 255.0f, value.a);
}
#endif
#ifdef ps_convert_float32_depth_to_color
void ps_convert_float32_depth_to_color()
{
o_col0 = sample_c(v_tex).r;
}
#endif
#ifdef ps_convert_float32_color_to_depth
void ps_convert_float32_color_to_depth()
{
gl_FragDepth = sample_c(v_tex).r;
}
#endif
#ifdef ps_convert_float32_32bits
void ps_convert_float32_32bits()
#ifdef ps_convert_depth32_32bits
void ps_convert_depth32_32bits()
{
// Convert a vec32 depth texture into a 32 bits UINT texture
o_col0 = uint(exp2(32.0f) * sample_c(v_tex).r);
OUTPUT = depth_to_uint(sample_c(v_tex));
}
#endif
#ifdef ps_convert_float32_rgba8
void ps_convert_float32_rgba8()
#ifdef ps_convert_depth32_rgba8
void ps_convert_depth32_rgba8()
{
// Convert a vec32 depth texture into a RGBA color texture
uint d = uint(sample_c(v_tex).r * exp2(32.0f));
o_col0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0);
OUTPUT = depth32_to_rgba8(sample_c(v_tex));
}
#endif
#ifdef ps_convert_float16_rgb5a1
void ps_convert_float16_rgb5a1()
#ifdef ps_convert_depth16_rgb5a1
void ps_convert_depth16_rgb5a1()
{
// Convert a vec32 (only 16 lsb) depth into a RGB5A1 color texture
uint d = uint(sample_c(v_tex).r * exp2(32.0f));
o_col0 = vec4(uvec4(d << 3, d >> 2, d >> 7, d >> 8) & uvec4(0xf8, 0xf8, 0xf8, 0x80)) / 255.0f;
OUTPUT = depth16_to_rgb5a1(sample_c(v_tex));
}
#endif
float rgba8_to_depth32(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
}
float rgba8_to_depth24(vec4 unorm)
{
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
}
float rgba8_to_depth16(vec4 unorm)
{
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
return float(c.r | (c.g << 8)) * exp2(-32.0f);
}
float rgb5a1_to_depth16(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
}
#ifdef ps_convert_float32_float24
void ps_convert_float32_float24()
#ifdef ps_convert_depth32_depth24
void ps_convert_depth32_depth24()
{
// Truncates depth value to 24bits
uint d = uint(sample_c(v_tex).r * exp2(32.0f)) & 0xFFFFFFu;
gl_FragDepth = float(d) * exp2(-32.0f);
}
#endif
#ifdef ps_convert_rgba8_float32
void ps_convert_rgba8_float32()
{
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth32(sample_c(v_tex));
}
#endif
#ifdef ps_convert_rgba8_float24
void ps_convert_rgba8_float24()
{
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth24(sample_c(v_tex));
}
#endif
#ifdef ps_convert_rgba8_float16
void ps_convert_rgba8_float16()
{
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth16(sample_c(v_tex));
}
#endif
#ifdef ps_convert_rgb5a1_float16
void ps_convert_rgb5a1_float16()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
gl_FragDepth = rgb5a1_to_depth16(sample_c(v_tex));
OUTPUT = depth32_to_depth24(sample_c(v_tex));
}
#endif
@@ -288,41 +291,53 @@ void ps_convert_rgb5a1_float16()
float depthTR = CONVERT_FN(texelFetch(samp0, coords.zy, 0)); \
float depthBL = CONVERT_FN(texelFetch(samp0, coords.xw, 0)); \
float depthBR = CONVERT_FN(texelFetch(samp0, coords.zw, 0)); \
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
OUTPUT = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
#ifdef ps_convert_rgba8_float32_biln
void ps_convert_rgba8_float32_biln()
#ifdef ps_convert_rgba8_depth32
void ps_convert_rgba8_depth32()
{
// Convert an RGBA texture into a float depth texture
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
#else
OUTPUT = rgba8_to_depth32(sample_c(v_tex));
#endif
}
#endif
#ifdef ps_convert_rgba8_float24_biln
void ps_convert_rgba8_float24_biln()
#ifdef ps_convert_rgba8_depth24
void ps_convert_rgba8_depth24()
{
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
#else
OUTPUT = rgba8_to_depth24(sample_c(v_tex));
#endif
}
#endif
#ifdef ps_convert_rgba8_float16_biln
void ps_convert_rgba8_float16_biln()
#ifdef ps_convert_rgba8_depth16
void ps_convert_rgba8_depth16()
{
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
#else
OUTPUT = rgba8_to_depth16(sample_c(v_tex));
#endif
}
#endif
#ifdef ps_convert_rgb5a1_float16_biln
void ps_convert_rgb5a1_float16_biln()
#ifdef ps_convert_rgb5a1_depth16
void ps_convert_rgb5a1_depth16()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
#if HAS_BILN
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
#else
OUTPUT = rgb5a1_to_depth16(sample_c(v_tex));
#endif
}
#endif
@@ -609,25 +624,25 @@ void ps_yuv()
}
#endif
#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1) || defined(ps_stencil_image_init_2) || defined(ps_stencil_image_init_3)
#if defined(ps_primid_image_init_0) || defined(ps_primid_image_init_1) || defined(ps_primid_image_init_2) || defined(ps_primid_image_init_3)
void main()
{
o_col0 = vec4(0x7FFFFFFF);
#ifdef ps_stencil_image_init_0
#ifdef ps_primid_image_init_0
if((127.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass)
o_col0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_1
#ifdef ps_primid_image_init_1
if(sample_c(v_tex).a < (127.5f / 255.0f)) // >= 0x80 pass
o_col0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_2
#ifdef ps_primid_image_init_2
if((254.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass)
o_col0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_3
#ifdef ps_primid_image_init_3
if(sample_c(v_tex).a < (254.5f / 255.0f)) // >= 0x80 pass
o_col0 = vec4(-1);
#endif
+174 -88
View File
@@ -24,7 +24,7 @@ layout(std140, set = 0, binding = 0) uniform cb0
vec2 TextureOffset;
vec2 PointSize;
uint MaxDepth;
uint pad_cb0;
float LineAA1Width;
};
layout(location = 0) out VSOutput
@@ -319,11 +319,9 @@ void main()
// Use bottom minus top for delta regardless of which vertex we are expanding.
vec2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy);
vec2 line_vector = normalize(line_delta / VertexScale);
#if VS_EXPAND == VS_EXPAND_LINE
vec2 line_expand = vec2(line_vector.y, -line_vector.x);
#elif VS_EXPAND == VS_EXPAND_LINE_AA1
// Expand in y direction for shallow lines and x direction for steep lines.
vec2 line_expand = abs(line_vector.x) >= abs(line_vector.y) ? vec2(0.0f, 2.0f) : vec2(2.0f, 0.0f);
#if VS_EXPAND == VS_EXPAND_LINE_AA1
line_expand *= 2.0f * LineAA1Width;
#endif
vec2 line_width = (line_expand * PointSize) / 2;
vec2 offset = is_right ? line_width : -line_width;
@@ -452,11 +450,6 @@ void main()
vsOut.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none.
vsOut.interior = 0;
#if !VS_IIP
// Get the provoking vertex color (last vertex in VK)
vtx.c = i0 == 2 ? vtx.c : (i1 == 2 ? other.c : opposite.c);
#endif
}
#endif
@@ -522,6 +515,12 @@ void main()
#define PS_AA1_TRIANGLE_SW_Z 3
#endif
#ifndef PS_ROV_DEPTH_NONE
#define PS_ROV_DEPTH_NONE 0
#define PS_ROV_DEPTH_READ_WRITE 1
#define PS_ROV_DEPTH_READ_ONLY 2
#endif
#ifndef PS_FST
#define PS_FST 0
#define PS_WMS 0
@@ -574,6 +573,8 @@ void main()
#define PS_NO_COLOR1 0
#define PS_DATE 0
#define PS_TEX_IS_FB 0
#define PS_ROV_COLOR 0
#define PS_ROV_DEPTH 0
#endif
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
@@ -586,7 +587,13 @@ void main()
#define PS_FEEDBACK_LOOP_IS_NEEDED_RT (PS_TEX_IS_FB == 1 || AFAIL_NEEDS_RT || PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW || (PS_DATE >= 5))
#define PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH (AFAIL_NEEDS_DEPTH || ZTST_NEEDS_DEPTH || AA1_NEEDS_DEPTH)
#define ZWRITE (PS_ZCLAMP || PS_ZFLOOR || PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH)
#define ZWRITE (PS_ZCLAMP || PS_ZFLOOR || SW_DEPTH || PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH)
#define PS_RETURN_COLOR_ROV (!PS_NO_COLOR && PS_ROV_COLOR)
#define PS_RETURN_COLOR (!PS_NO_COLOR && !PS_ROV_COLOR)
#define PS_RETURN_DEPTH_ROV (PS_ROV_DEPTH == PS_ROV_DEPTH_READ_WRITE)
#define PS_RETURN_DEPTH (ZWRITE && !PS_ROV_DEPTH)
#define PS_ROV_EARLYDEPTHSTENCIL (PS_ROV_COLOR && !PS_ROV_DEPTH && !ZWRITE)
#define NEEDS_TEX (PS_TFX != 4)
@@ -610,6 +617,12 @@ layout(std140, set = 0, binding = 1) uniform cb1
mat4 DitherMatrix;
float ScaledScaleFactor;
float RcpScaleFactor;
float _pad0_cb1;
float _pad1_cb1;
float LineCovScale;
float _pad2_cb1;
float _pad3_cb1;
float _pad4_cb1;
};
layout(location = 0) in VSOutput
@@ -625,11 +638,27 @@ layout(location = 0) in VSOutput
flat uint interior; // 1 for triangle interior; 0 for edge;
} vsIn;
#if !PS_NO_COLOR && !PS_NO_COLOR1
layout(location = 0, index = 0) out vec4 o_col0;
layout(location = 0, index = 1) out vec4 o_col1;
#elif !PS_NO_COLOR
layout(location = 0) out vec4 o_col0;
#if PS_RETURN_COLOR
#if !PS_NO_COLOR1
layout(location = 0, index = 0) out vec4 o_col0;
layout(location = 0, index = 1) out vec4 o_col1;
#elif !PS_NO_COLOR
layout(location = 0) out vec4 o_col0;
#endif
#elif PS_RETURN_COLOR_ROV
vec4 o_col0;
#endif
#if PS_ROV_COLOR
layout(set = 1, binding = 5, rgba8) uniform restrict coherent image2D RtImageRov;
vec4 rov_rt_value;
vec4 sample_from_rt() { return rov_rt_value; }
#endif
#if PS_ROV_DEPTH
layout(set = 1, binding = 6, r32f) uniform restrict coherent image2D DepthImageRov;
float rov_depth_value;
float sample_from_depth() { return rov_depth_value; }
#endif
#if NEEDS_TEX
@@ -639,27 +668,27 @@ layout(set = 1, binding = 1) uniform texture2D Palette;
#if PS_FEEDBACK_LOOP_IS_NEEDED_RT || PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH
#if defined(DISABLE_TEXTURE_BARRIER) || defined(HAS_FEEDBACK_LOOP_LAYOUT)
#if PS_FEEDBACK_LOOP_IS_NEEDED_RT
#if (PS_FEEDBACK_LOOP_IS_NEEDED_RT && !PS_ROV_COLOR)
layout(set = 1, binding = 2) uniform texture2D RtSampler;
vec4 sample_from_rt() { return texelFetch(RtSampler, ivec2(gl_FragCoord.xy), 0); }
#endif
#if PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH
#if (PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH && !PS_ROV_DEPTH)
layout(set = 1, binding = 4) uniform texture2D DepthSampler;
vec4 sample_from_depth() { return texelFetch(DepthSampler, ivec2(gl_FragCoord.xy), 0); }
float sample_from_depth() { return texelFetch(DepthSampler, ivec2(gl_FragCoord.xy), 0).r; }
#endif
#else
// Must consider each case separately since the input attachment indices must be consecutive.
#if PS_FEEDBACK_LOOP_IS_NEEDED_RT && PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH
#if (PS_FEEDBACK_LOOP_IS_NEEDED_RT && !PS_ROV_COLOR) && (PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH && !PS_ROV_DEPTH)
layout(input_attachment_index = 0, set = 1, binding = 2) uniform subpassInput RtSampler;
layout(input_attachment_index = 1, set = 1, binding = 4) uniform subpassInput DepthSampler;
vec4 sample_from_rt() { return subpassLoad(RtSampler); }
vec4 sample_from_depth() { return subpassLoad(DepthSampler); }
#elif PS_FEEDBACK_LOOP_IS_NEEDED_RT
float sample_from_depth() { return subpassLoad(DepthSampler).r; }
#elif (PS_FEEDBACK_LOOP_IS_NEEDED_RT && !PS_ROV_COLOR)
layout(input_attachment_index = 0, set = 1, binding = 2) uniform subpassInput RtSampler;
vec4 sample_from_rt() { return subpassLoad(RtSampler); }
#elif PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH
#elif (PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH && !PS_ROV_DEPTH)
layout(input_attachment_index = 0, set = 1, binding = 4) uniform subpassInput DepthSampler;
vec4 sample_from_depth() { return subpassLoad(DepthSampler); }
float sample_from_depth() { return subpassLoad(DepthSampler).r; }
#endif
#endif
#endif
@@ -694,22 +723,27 @@ float manual_lod(float uv_w)
vec4 sample_c_af(vec2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = (any(isnan(uv)) || any(isinf(uv))) ? vec2(0, 0) : uv;
uv = (any(isnan(uv)) || any(isinf(uv))) ? vec2(0.0f, 0.0f) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// And https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_filter_anisotropic.txt
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
vec2 sz = textureSize(Texture, 0);
vec2 dX = dFdx(uv) * sz;
vec2 dY = dFdy(uv) * sz;
float length_x = length(dX);
float length_y = length(dY);
// Calculate Ellipse Transform
bool d_zero = length(dX) == 0 || length(dY) == 0;
bool d_par = (dX.x * dY.y - dY.x * dX.y) == 0;
bool d_per = dot(dX, dY) == 0;
bool d_zero = length_x < 0.001f || length_y < 0.001f;
float f = (dX.x * dY.y - dX.y * dY.x);
bool d_par = f < 0.001f;
bool d_per = dot(dX, dY) < 0.001f;
bool d_inf_nan = any(isinf(dX)) || any(isinf(dY)) || any(isnan(dX)) || any(isnan(dY));
if (!(d_zero || d_par || d_per || d_inf_nan))
@@ -724,31 +758,40 @@ vec4 sample_c_af(vec2 uv, float uv_w)
float q = A + C;
float t = sqrt(p * p + B * B);
float signB = sign(B);
float denom_plus = t * (q + t);
float denom_minus = t * (q - t);
float sqrtA = sqrt(F * (t + p));
float sqrtB = sqrt(F * (t - p));
float inv_sqrt_denom_plus = inversesqrt(denom_plus);
float inv_sqrt_denom_minus = inversesqrt(denom_minus);
vec2 new_dX = vec2(
sqrt(F * (t + p) / (t * (q + t))),
sqrt(F * (t - p) / (t * (q + t))) * sign(B)
sqrtA * inv_sqrt_denom_plus,
sqrtB * inv_sqrt_denom_plus * signB
);
vec2 new_dY = vec2(
sqrt(F * (t - p) / (t * (q - t))) * -sign(B),
sqrt(F * (t + p) / (t * (q - t)))
sqrtB * inv_sqrt_denom_minus * -signB,
sqrtA * inv_sqrt_denom_minus
);
d_inf_nan = any(isinf(new_dX)) || any(isinf(new_dY)) || any(isnan(new_dX)) || any(isnan(new_dY));
if (!d_inf_nan)
{
dX = new_dX;
dY = new_dY;
length_x = length(dX);
length_y = length(dY);
}
}
// Compute AF values
float squared_length_x = dX.x * dX.x + dX.y * dX.y;
float squared_length_y = dY.x * dY.x + dY.y * dY.y;
float determinant = abs(dX.x * dY.y - dX.y * dY.x);
bool is_major_x = squared_length_x > squared_length_y;
float squared_length_major = is_major_x ? squared_length_x : squared_length_y;
float length_major = sqrt(squared_length_major);
bool is_major_x = length_x > length_y;
float length_major = is_major_x ? length_x : length_y;
float length_minor = is_major_x ? length_y : length_x;
float aniso_ratio;
float length_lod;
@@ -760,57 +803,42 @@ vec4 sample_c_af(vec2 uv, float uv_w)
// Perform isotropic filtering instead.
aniso_ratio = 1.0f;
length_lod = length_major;
aniso_line = vec2(0, 0);
aniso_line = vec2(0.0f, 0.0f);
}
else
{
float norm_major = 1.0f / length_major;
vec2 aniso_line_dir = vec2(
(is_major_x ? dX.x : dY.x) * norm_major,
(is_major_x ? dX.y : dY.y) * norm_major
);
aniso_ratio = squared_length_major / determinant;
vec2 aniso_line_dir = is_major_x ? dX : dY;
// Calculate the minor length of the ellipse for Lod, while also clamping the ratio of anisotropy.
if (aniso_ratio > PS_ANISOTROPIC_FILTERING)
{
// ratio is clamped - Lod is based on ratio (preserves area)
aniso_ratio = PS_ANISOTROPIC_FILTERING;
length_lod = length_major / PS_ANISOTROPIC_FILTERING;
}
else
{
// ratio not clamped - Lod is based on area
length_lod = determinant / length_major;
}
aniso_ratio = min(length_major / length_minor, PS_ANISOTROPIC_FILTERING);
length_lod = length_major / aniso_ratio;
// clamp to top Lod
if (length_lod < 1.0f)
aniso_ratio = max(1.0f, aniso_ratio * length_lod);
aniso_ratio = round(aniso_ratio);
aniso_line = aniso_line_dir * 0.5f * length_major * (1.0f / sz);
aniso_line = aniso_line_dir * 0.5f * (1.0f / sz);
}
#if PS_AUTOMATIC_LOD == 1
float lod = log2(length_lod);
#elif PS_MANUAL_LOD == 1
float lod = manual_lod(uv_w);
#else
float lod = 0; // No Lod
float lod = 0.0f; // No Lod
#endif
vec4 colour;
if (aniso_ratio == 1.0f)
colour = textureLod(Texture, uv, lod);
else
{
vec4 num = vec4(0, 0, 0, 0);
vec4 num = vec4(0.0f, 0.0f, 0.0f, 0.0f);
vec2 segment = (2.0f * aniso_line) / aniso_ratio;
for (int i = 0; i < aniso_ratio; i++)
{
vec2 d = -aniso_line + (0.5f + i) * (2.0f * aniso_line) / aniso_ratio;
{
vec2 d = -aniso_line + (0.5f + i) * segment;
vec2 uv_sample = uv + d;
vec4 sample_colour = textureLod(Texture, uv_sample, lod);
num += sample_colour;
@@ -1114,7 +1142,7 @@ vec4 sample_depth(vec2 st, ivec2 pos)
}
#elif (PS_DEPTH_FMT == 1)
{
// Based on ps_convert_float32_rgba8 of convert
// Based on ps_convert_depth32_rgba8 of convert
// Convert a vec32 depth texture into a RGBA color texture
uint d = uint(fetch_c(uv).r * exp2(32.0f));
@@ -1122,7 +1150,7 @@ vec4 sample_depth(vec2 st, ivec2 pos)
}
#elif (PS_DEPTH_FMT == 2)
{
// Based on ps_convert_float16_rgb5a1 of convert
// Based on ps_convert_depth16_rgb5a1 of convert
// Convert a vec32 (only 16 lsb) depth into a RGB5A1 color texture
uint d = uint(fetch_c(uv).r * exp2(32.0f));
@@ -1604,7 +1632,7 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
#elif PS_BLEND_MIX == 1
Color.rgb = ((A - B) * C_clamped + D) - (124.0f/256.0f);
#else
Color.rgb = trunc((A - B) * C + D);
Color.rgb = trunc((A - B) * C + D);
#endif
#if PS_BLEND_HW == 1
@@ -1678,6 +1706,24 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
#endif
}
#if PS_ROV_COLOR || PS_ROV_DEPTH
layout(pixel_interlock_ordered) in;
#endif
#if PS_ROV_EARLYDEPTHSTENCIL
layout(early_fragment_tests) in;
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
#define DISCARD { rov_discard_color = true; rov_discard_depth = true; }
#define DISCARD_COLOR rov_discard_color = true
#define DISCARD_DEPTH rov_discard_depth = true
#else
#define DISCARD discard
#define DISCARD_COLOR o_col0 = sample_from_rt()
#define DISCARD_DEPTH input_z = sample_from_depth()
#endif
void main()
{
float input_z = gl_FragCoord.z;
@@ -1687,18 +1733,35 @@ void main()
input_z = floor(input_z * exp2(32.0f)) * exp2(-32.0f);
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
beginInvocationInterlockARB();
#endif
#if PS_ROV_COLOR
rov_rt_value = imageLoad(RtImageRov, ivec2(gl_FragCoord.xy));
#endif
#if PS_ROV_DEPTH
rov_depth_value = imageLoad(DepthImageRov, ivec2(gl_FragCoord.xy)).r;
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
bool rov_discard_color = gl_HelperInvocation;
bool rov_discard_depth = gl_HelperInvocation;
#endif
#if PS_ZTST == ZTST_GEQUAL
if (input_z < sample_from_depth().r)
discard;
if (input_z < sample_from_depth())
DISCARD;
#elif PS_ZTST == ZTST_GREATER
if (input_z <= sample_from_depth().r)
discard;
if (input_z <= sample_from_depth())
DISCARD;
#endif
#if PS_SCANMSK & 2
// fail depth test on prohibited lines
if ((int(gl_FragCoord.y) & 1) == (PS_SCANMSK & 1))
discard;
DISCARD;
#endif
#if PS_DATE >= 5
@@ -1726,7 +1789,7 @@ void main()
#endif
if (bad) {
discard;
DISCARD;
}
#endif // PS_DATE >= 5
@@ -1737,14 +1800,19 @@ void main()
// the bad alpha value so we must keep it.
if (gl_PrimitiveID > stencil_ceil) {
discard;
DISCARD;
}
#endif
vec4 C = ps_color();
#if PS_AA1
float cov = clamp(1.0f - abs(vsIn.inv_cov), 0.0f, 1.0f);
#if PS_AA1 == PS_AA1_LINE
// Blur only outer part of the line by scaling coverage.
float cov = clamp(LineCovScale * (1.0f - abs(vsIn.inv_cov)), 0.0f, 1.0f);
#else
float cov = clamp(1.0f - abs(vsIn.inv_cov), 0.0f, 1.0f);
#endif
#if PS_ABE
if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.0f * cov;
@@ -1758,9 +1826,10 @@ void main()
bool atst_pass = atst(C);
#if PS_AFAIL == AFAIL_KEEP
if (!atst_pass)
discard;
#if PS_ATST != PS_ATST_NONE && PS_AFAIL == AFAIL_KEEP
if (!atst_pass) {
DISCARD;
}
#endif
#if SW_AD_TO_HW
@@ -1852,6 +1921,7 @@ void main()
alpha_blend.a = float(atst_pass);
#endif
// Output color scaling
#if !PS_NO_COLOR
#if PS_RTA_CORRECTION
o_col0.a = C.a / 128.0f;
@@ -1870,16 +1940,16 @@ void main()
// Alpha test with feedback
#if PS_AFAIL == AFAIL_FB_ONLY
if (!atst_pass)
input_z = sample_from_depth().r;
DISCARD_DEPTH;
#elif PS_AFAIL == AFAIL_ZB_ONLY
if (!atst_pass)
o_col0 = sample_from_rt();
DISCARD_COLOR;
#elif (PS_AFAIL == AFAIL_RGB_ONLY || PS_AFAIL == AFAIL_RGB_ONLY_SW_Z)
if (!atst_pass)
{
o_col0.a = sample_from_rt().a;
o_col0.a = sample_from_rt().a; // discard alpha
#if PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
input_z = sample_from_depth().r;
DISCARD_DEPTH;
#endif
}
#endif
@@ -1891,11 +1961,27 @@ void main()
#if PS_AA1 == PS_AA1_TRIANGLE_SW_Z
if (!bool(vsIn.interior))
input_z = sample_from_depth().r; // No depth update for triangle edges.
DISCARD_DEPTH; // No depth update for triangle edges.
#endif
#if ZWRITE
// Writing back color (result already written to o_col0 for non-ROV)
#if PS_RETURN_COLOR_ROV
o_col0 = mix(o_col0, sample_from_rt(), equal(FbMask, uvec4(0xFFu))); // channel masking
if (!rov_discard_color)
imageStore(RtImageRov, ivec2(gl_FragCoord.xy), o_col0);
#endif
// Writing back depth
#if PS_RETURN_DEPTH
gl_FragDepth = input_z;
#elif PS_RETURN_DEPTH_ROV
if (!rov_discard_depth)
imageStore(DepthImageRov, ivec2(gl_FragCoord.xy), vec4(input_z, 0, 0, 1.0f));
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
endInvocationInterlockARB();
#endif
#endif // PS_DATE
}
+2 -2
View File
@@ -300,8 +300,8 @@ else()
if(CMAKE_INTERPROCEDURAL_OPTIMIZATION)
message(WARNING
"The CMAKE_INTERPROCEDURAL_OPTIMIZATION option is enabled but the "
"CMAKE_POSITION_INDEPENDENT_CODE option is disabled. This has been "
"found to result in broken builds on certain platforms.")
"POSITION_INDEPENDENT_CODE option is disabled. This has been found "
"to result in broken builds on certain platforms.")
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE OFF)
+3
View File
@@ -22,6 +22,9 @@ find_package(Freetype 2.10 REQUIRED) # 2.10 is the first with COLRv0 support, wh
find_package(plutovg 1.1.0 REQUIRED)
find_package(plutosvg 0.0.7 REQUIRED)
find_package(ryml REQUIRED)
if (WIN32)
find_package(DirectX-Headers 1.618.1 REQUIRED)
endif()
if(USE_VULKAN)
find_package(Shaderc REQUIRED)
+13 -3
View File
@@ -98,14 +98,25 @@ __ri void Log::WriteToConsole(LOGLEVEL level, ConsoleColors color, std::string_v
static constexpr size_t BUFFER_SIZE = 512;
#ifdef _WIN32
constexpr bool supports_color_codes = true;
#else
const int fd = (level <= LOGLEVEL_WARNING) ? STDERR_FILENO : STDOUT_FILENO;
const bool supports_color_codes = static_cast<bool>(isatty(fd));
#endif
SmallStackString<BUFFER_SIZE> buffer;
buffer.reserve(static_cast<u32>(32 + message.length()));
buffer.append(s_ansi_color_codes[color]);
if (supports_color_codes)
buffer.append(s_ansi_color_codes[color]);
if (s_log_timestamps)
buffer.append_format(TIMESTAMP_FORMAT_STRING, Log::GetCurrentMessageTime());
buffer.append(message);
if (supports_color_codes)
buffer.append(s_ansi_color_codes[Color_Default]);
buffer.append('\n');
#ifdef _WIN32
@@ -134,7 +145,6 @@ cleanup:
if (wmessage_buf != wbuf)
std::free(wmessage_buf);
#else
const int fd = (level <= LOGLEVEL_WARNING) ? STDERR_FILENO : STDOUT_FILENO;
write(fd, buffer.data(), buffer.length());
#endif
}
@@ -157,7 +167,7 @@ void Log::SetConsoleOutputLevel(LOGLEVEL level)
if (was_enabled == now_enabled)
return;
// Worst that happens here is we write to a bad handle..
// Worst that happens here is we write to a bad handle..
#if defined(_WIN32)
static constexpr auto enable_virtual_terminal_processing = [](HANDLE hConsole) {
+39
View File
@@ -34,6 +34,34 @@ Value MemoryInterface::Read(u32 address, bool* valid)
return Value(0);
}
std::optional<std::string> MemoryInterface::ReadString(u32 address, u32 max_size, ReadStringFlags flags)
{
std::string string;
for (u32 i = 0; i < max_size; i++)
{
bool valid;
char c = Read8(address + i, &valid);
if (!valid)
return std::nullopt;
if (c == '\0')
return string;
else if (!(flags & ALLOW_NON_PRINTABLE_CHARACTERS) && (c < ' ' || c > '~'))
return std::nullopt;
string += c;
}
if (flags & ALLOW_LONG_STRINGS)
{
string += '~';
return string;
}
return std::nullopt;
}
template <MemoryAccessType Value>
bool MemoryInterface::Write(u32 address, Value value)
{
@@ -62,6 +90,17 @@ bool MemoryInterface::Write(u32 address, Value value)
return false;
}
bool MemoryInterface::WriteString(u32 address, std::string_view string)
{
if (!WriteBytes(address, string.data(), static_cast<u32>(string.size())))
return false;
if (!Write8(address + static_cast<u32>(string.size()), '\0'))
return false;
return true;
}
bool MemoryInterface::IdempotentWrite8(u32 address, u8 value)
{
bool valid;
+16 -2
View File
@@ -5,6 +5,9 @@
#include "Pcsx2Types.h"
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
template <typename Value>
@@ -31,16 +34,27 @@ public:
template <MemoryAccessType Value>
Value Read(u32 address, bool* valid = nullptr);
enum ReadStringFlags
{
NO_FLAGS = 0,
ALLOW_LONG_STRINGS = 1 << 0,
ALLOW_NON_PRINTABLE_CHARACTERS = 1 << 1
};
std::optional<std::string> ReadString(u32 address, u32 max_size = 256, ReadStringFlags flags = NO_FLAGS);
virtual bool Write8(u32 address, u8 value) = 0;
virtual bool Write16(u32 address, u16 value) = 0;
virtual bool Write32(u32 address, u32 value) = 0;
virtual bool Write64(u32 address, u64 value) = 0;
virtual bool Write128(u32 address, u128 value) = 0;
virtual bool WriteBytes(u32 address, void* src, u32 size) = 0;
virtual bool WriteBytes(u32 address, const void* src, u32 size) = 0;
template <MemoryAccessType Value>
bool Write(u32 address, Value value);
bool WriteString(u32 address, std::string_view string);
bool IdempotentWrite8(u32 address, u8 value);
bool IdempotentWrite16(u32 address, u16 value);
bool IdempotentWrite32(u32 address, u32 value);
@@ -51,5 +65,5 @@ public:
template <MemoryAccessType Value>
bool IdempotentWrite(u32 address, Value value);
virtual bool CompareBytes(u32 address, void* src, u32 size) = 0;
virtual bool CompareBytes(u32 address, const void* src, u32 size) = 0;
};
+88 -26
View File
@@ -17,7 +17,7 @@ struct RapidYAMLContext
Error* error = nullptr;
};
std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr file_name, Error* error)
std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr file_name, Error* error, bool resolve_anchors)
{
RapidYAMLContext context;
context.error = error;
@@ -28,40 +28,93 @@ std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr
callbacks.set_user_data(static_cast<void*>(&context));
callbacks.set_error_basic([](ryml::csubstr msg, const ryml::ErrorDataBasic& errdata, void* user_data) {
std::string description;
auto callback = [&description](ryml::csubstr string) {
description.append(string.str, string.len);
};
ryml::err_basic_format(std::move(callback), msg, errdata);
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
// This scope needs to stay, so all objects destruct before std::longjump
{
std::string description;
auto callback = [&description](ryml::csubstr string) {
description.append(string.str, string.len);
};
ryml::err_basic_format(std::move(callback), msg, errdata);
// We might have already returned, so don't try to recover.
pxFailRel(description.c_str());
std::abort();
if (context != nullptr)
{
Error::SetString(context->error, std::move(description));
}
else
{
pxFailRel(description.c_str());
}
}
if (context != nullptr)
{
std::longjmp(context->env, 1);
}
else
{
std::terminate();
}
});
callbacks.set_error_parse([](ryml::csubstr msg, const ryml::ErrorDataParse& errdata, void* user_data) {
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
// This scope needs to stay, so all objects destruct before std::longjump
{
std::string description;
auto callback = [&description](ryml::csubstr string) {
description.append(string.str, string.len);
};
ryml::err_parse_format(std::move(callback), msg, errdata);
std::string description;
auto callback = [&description](ryml::csubstr string) {
description.append(string.str, string.len);
};
ryml::err_parse_format(std::move(callback), msg, errdata);
if (context != nullptr)
{
Error::SetString(context->error, std::move(description));
}
else
{
pxFailRel(description.c_str());
}
}
Error::SetString(context->error, std::move(description));
std::longjmp(context->env, 1);
if (context != nullptr)
{
std::longjmp(context->env, 2);
}
else
{
std::terminate();
}
});
callbacks.set_error_visit([](ryml::csubstr msg, const ryml::ErrorDataVisit& errdata, void* user_data) {
std::string description;
auto callback = [&description](ryml::csubstr string) {
description.append(string.str, string.len);
};
ryml::err_visit_format(std::move(callback), msg, errdata);
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
// This scope needs to stay, so all objects destruct before std::longjump
{
std::string description;
auto callback = [&description](ryml::csubstr string) {
description.append(string.str, string.len);
};
ryml::err_visit_format(std::move(callback), msg, errdata);
// We've probably already returned, so don't try to recover.
pxFailRel(description.c_str());
std::abort();
if (context != nullptr)
{
Error::SetString(context->error, std::move(description));
}
else
{
pxFailRel(description.c_str());
}
}
if (context != nullptr)
{
std::longjmp(context->env, 3);
}
else
{
std::terminate();
}
});
#else
callbacks.m_user_data = static_cast<void*>(&context);
@@ -76,15 +129,24 @@ std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr
ryml::EventHandlerTree event_handler(callbacks);
ryml::Parser parser(&event_handler);
ryml::Tree tree;
ryml::Tree tree(callbacks);
// The only options RapidYAML provides for recovering from errors are
// throwing an exception or using setjmp/longjmp. Since we have exceptions
// disabled we have to use the latter option.
if (setjmp(context.env))
if (setjmp(context.env) != 0)
return std::nullopt;
ryml::parse_in_arena(&parser, file_name, yaml, &tree);
if (resolve_anchors)
{
tree.resolve();
}
// Callbacks passed to ryml::Tree are used for value parsing errors later,
// so we need to clear the context before it goes out of scope.
callbacks.set_user_data(nullptr);
tree.callbacks(callbacks);
return tree;
}
+3 -1
View File
@@ -14,4 +14,6 @@
/// parsing errors (as is recommended by the documentation for cases where
/// exceptions are disabled). The file_name parameter is only used for error
/// messages, which are returned via the error parameter.
std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr file_name, Error* error);
/// If resolve_anchors is set to true, YAML anchors and aliases will be resolved.
/// It's a potentially slow operation, so it's opt-in.
std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr file_name, Error* error, bool resolve_anchors = false);
+1
View File
@@ -163,6 +163,7 @@
<ClInclude Include="WindowInfo.h" />
<ClInclude Include="YAML.h" />
<ClInclude Include="Threading.h" />
<ClInclude Include="EnumOps.h" />
<ClInclude Include="emitter\implement\avx.h" />
<ClInclude Include="emitter\implement\bmi.h" />
<ClInclude Include="emitter\instructions.h" />
-2
View File
@@ -30,8 +30,6 @@ namespace x86Emitter
extern void EmitRex(SIMDInstructionInfo info, const xRegisterBase& reg1, const xRegisterBase& reg2);
extern void EmitRex(SIMDInstructionInfo info, const xRegisterBase& reg1, const xIndirectVoid& sib);
extern void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from);
template <typename T>
inline void xWrite(T val)
{
+1 -7
View File
@@ -22,7 +22,7 @@
namespace x86Emitter
{
void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from)
void xImpl_Mov::operator()(const xRegisterInt& to, const xRegisterInt& from) const
{
pxAssert(to.GetOperandSize() == from.GetOperandSize());
@@ -32,12 +32,6 @@ namespace x86Emitter
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, to);
}
void xImpl_Mov::operator()(const xRegisterInt& to, const xRegisterInt& from) const
{
// FIXME WTF?
_xMovRtoR(to, from);
}
void xImpl_Mov::operator()(const xIndirectVoid& dest, const xRegisterInt& from) const
{
// mov eax has a special from when writing directly to a DISP32 address
+6 -6
View File
@@ -1045,7 +1045,7 @@ const xRegister32
}
else if (displacement_size == 0)
{
_xMovRtoR(to, src.Index.MatchSizeTo(to));
xMOV(to, src.Index.MatchSizeTo(to));
return;
}
else if (!preserve_flags)
@@ -1053,7 +1053,7 @@ const xRegister32
// encode as MOV and ADD combo. Make sure to use the immediate on the
// ADD since it can encode as an 8-bit sign-extended value.
_xMovRtoR(to, src.Index.MatchSizeTo(to));
xMOV(to, src.Index.MatchSizeTo(to));
xADD(to, src.Displacement);
return;
}
@@ -1071,7 +1071,7 @@ const xRegister32
// (this does not apply to older model P4s with the broken barrel shifter,
// but we currently aren't optimizing for that target anyway).
_xMovRtoR(to, src.Index);
xMOV(to, src.Index);
xSHL(to, src.Scale);
return;
}
@@ -1085,14 +1085,14 @@ const xRegister32
if (src.Index == rsp)
{
// ESP is not encodable as an index (ix86 ignores it), thus:
_xMovRtoR(to, src.Base.MatchSizeTo(to)); // will do the trick!
xMOV(to, src.Base.MatchSizeTo(to)); // will do the trick!
if (src.Displacement)
xADD(to, src.Displacement);
return;
}
else if (src.Displacement == 0)
{
_xMovRtoR(to, src.Base.MatchSizeTo(to));
xMOV(to, src.Base.MatchSizeTo(to));
xADD(to, src.Index.MatchSizeTo(to));
return;
}
@@ -1102,7 +1102,7 @@ const xRegister32
// special case handling of ESP as Index, which is replaceable with
// a single MOV even when preserve_flags is set! :D
_xMovRtoR(to, src.Base.MatchSizeTo(to));
xMOV(to, src.Base.MatchSizeTo(to));
return;
}
}
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DepsRootDir Condition="'$(Platform)'=='x64'">$(SolutionDir)deps\</DepsRootDir>
<DepsRootDir Condition="'$(Platform)'=='ARM64'">$(SolutionDir)deps-arm64\</DepsRootDir>
<DepsBinDir>$(DepsRootDir)bin\</DepsBinDir>
<DepsLibDir>$(DepsRootDir)lib\</DepsLibDir>
<DepsIncludeDir>$(DepsRootDir)include\</DepsIncludeDir>
</PropertyGroup>
</Project>
+3 -5
View File
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets">
<Import Project="DepsDir.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros">
<SSEString />
<SSEString Condition="$(Configuration.Contains(AVX2))">-avx2</SSEString>
@@ -15,11 +18,6 @@
<PropertyGroup>
<OutDir>$(SolutionDir)build\lib-$(PlatformName)-$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\obj-$(ProjectName)-$(PlatformName)-$(Configuration)\</IntDir>
<DepsRootDir Condition="'$(Platform)'=='x64'">$(SolutionDir)deps\</DepsRootDir>
<DepsRootDir Condition="'$(Platform)'=='ARM64'">$(SolutionDir)deps-arm64\</DepsRootDir>
<DepsBinDir>$(DepsRootDir)bin\</DepsBinDir>
<DepsLibDir>$(DepsRootDir)lib\</DepsLibDir>
<DepsIncludeDir>$(DepsRootDir)include\</DepsIncludeDir>
</PropertyGroup>
<PropertyGroup>
<LinkIncremental>false</LinkIncremental>
+17 -10
View File
@@ -91,6 +91,9 @@ static double s_last_barriers = 0;
static double s_last_copies = 0;
static double s_last_uploads = 0;
static double s_last_readbacks = 0;
static double s_last_depth_copies_rov = 0;
static double s_last_draws_rov = 0;
static double s_last_barriers_rov = 0;
static u64 s_total_internal_draws = 0;
static u64 s_total_draws = 0;
static u64 s_total_render_passes = 0;
@@ -98,6 +101,9 @@ static u64 s_total_barriers = 0;
static u64 s_total_copies = 0;
static u64 s_total_uploads = 0;
static u64 s_total_readbacks = 0;
static u64 s_total_copies_rov = 0;
static u64 s_total_draws_rov = 0;
static u64 s_total_barriers_rov = 0;
static u32 s_total_frames = 0;
static u32 s_total_drawn_frames = 0;
@@ -216,6 +222,11 @@ bool Host::CopyTextToClipboard(const std::string_view text)
return false;
}
std::string Host::GetTextFromClipboard()
{
return std::string();
}
void Host::BeginTextInput()
{
// noop
@@ -287,6 +298,9 @@ void Host::BeginPresentFrame()
update_stat(GSPerfMon::TextureCopies, s_total_copies, s_last_copies);
update_stat(GSPerfMon::TextureUploads, s_total_uploads, s_last_uploads);
update_stat(GSPerfMon::Readbacks, s_total_readbacks, s_last_readbacks);
update_stat(GSPerfMon::TextureCopiesROV, s_total_copies_rov, s_last_depth_copies_rov);
update_stat(GSPerfMon::DrawCallsROV, s_total_draws_rov, s_last_draws_rov);
update_stat(GSPerfMon::BarriersROV, s_total_barriers_rov, s_last_barriers_rov);
const bool idle_frame = s_total_frames && (last_draws == s_total_internal_draws && last_uploads == s_total_uploads);
@@ -419,16 +433,6 @@ void Host::OnAchievementsRefreshed()
// noop
}
void Host::OnCoverDownloaderOpenRequested()
{
// noop
}
void Host::OnCreateMemoryCardOpenRequested()
{
// noop
}
bool Host::InBatchMode()
{
return false;
@@ -913,6 +917,9 @@ void GSRunner::DumpStats()
Console.WriteLn(fmt::format("@HWSTAT@ Copies: {} (avg {})", s_total_copies, static_cast<u64>(std::ceil(s_total_copies / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Uploads: {} (avg {})", s_total_uploads, static_cast<u64>(std::ceil(s_total_uploads / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Readbacks: {} (avg {})", s_total_readbacks, static_cast<u64>(std::ceil(s_total_readbacks / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Copies (ROV): {} (avg {})", s_total_copies_rov, static_cast<u64>(std::ceil(s_total_copies_rov / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Draws Calls (ROV): {} (avg {})", s_total_draws_rov, static_cast<u64>(std::ceil(s_total_draws_rov / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Barriers (ROV): {} (avg {})", s_total_barriers_rov, static_cast<u64>(std::ceil(s_total_barriers_rov / static_cast<double>(s_total_drawn_frames)))));
if (s_perf_enable)
{
Console.WriteLn(fmt::format("@HWSTAT@ Minimum Frame Time: {:.3f} ms ({:.3f} FPS)", PerformanceMetrics::GetMinimumFrameTime(), 1000.0f / PerformanceMetrics::GetMinimumFrameTime()));
+9 -9
View File
@@ -50,15 +50,15 @@ private:
QWidget* parent;
MemoryViewType displayType = MemoryViewType::BYTE;
bool littleEndian = true;
u32 rowCount;
u32 rowVisible;
s32 rowHeight;
u32 rowCount = 0;
u32 rowVisible = 0;
s32 rowHeight = 0;
// Stuff used for selection handling
// This gets set every paint and depends on the window size / current display mode (1byte,2byte,etc)
s32 valuexAxis; // Where the hexadecimal view begins
s32 textXAxis; // Where the text view begins
s32 row1YAxis; // Where the first row starts
s32 valuexAxis = 0; // Where the hexadecimal view begins
s32 textXAxis = 0; // Where the text view begins
s32 row1YAxis = 0; // Where the first row starts
s32 segmentXAxis[16]; // Where the segments begin
bool selectedText = false; // Whether the user has clicked on text or hex
@@ -89,9 +89,9 @@ public:
{
}
u32 startAddress;
u32 selectedAddress;
s32 selectedIndex;
u32 startAddress = 0;
u32 selectedAddress = 0;
s32 selectedIndex = 0;
void UpdateStartAddress(u32 start);
void UpdateSelectedAddress(u32 selected, bool page = false);
@@ -7,6 +7,8 @@
#include "Debugger/SymbolTree/SymbolTreeModel.h"
#include "Debugger/SymbolTree/TypeString.h"
#include "common/StringUtil.h"
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QDoubleSpinBox>
@@ -44,12 +46,28 @@ QWidget* SymbolTreeValueDelegate::createEditor(QWidget* parent, const QStyleOpti
const ccc::ast::Node& physical_type = *logical_type->physical_type(database).first;
QVariant value = node->readValueAsVariant(physical_type, m_cpu, database);
const ccc::ast::Node& type = *logical_type->physical_type(database).first;
switch (type.descriptor)
switch (physical_type.descriptor)
{
case ccc::ast::ARRAY:
{
const ccc::ast::Array& array = physical_type.as<ccc::ast::Array>();
const ccc::ast::Node& element_type = *array.element_type->physical_type(database).first;;
if (array.element_count > 0 &&
element_type.name == "char" &&
node->location.type == SymbolTreeLocation::MEMORY &&
!value.isNull())
{
QLineEdit* editor = new QLineEdit(parent);
editor->setText(value.toString());
result = editor;
}
break;
}
case ccc::ast::BUILTIN:
{
const ccc::ast::BuiltIn& builtin = type.as<ccc::ast::BuiltIn>();
const ccc::ast::BuiltIn& builtin = physical_type.as<ccc::ast::BuiltIn>();
switch (builtin.bclass)
{
@@ -111,7 +129,7 @@ QWidget* SymbolTreeValueDelegate::createEditor(QWidget* parent, const QStyleOpti
}
case ccc::ast::ENUM:
{
const ccc::ast::Enum& enumeration = type.as<ccc::ast::Enum>();
const ccc::ast::Enum& enumeration = physical_type.as<ccc::ast::Enum>();
QComboBox* combo_box = new QComboBox(parent);
bool named = false;
@@ -186,12 +204,30 @@ void SymbolTreeValueDelegate::setModelData(QWidget* editor, QAbstractItemModel*
if (!logical_type)
return;
const ccc::ast::Node& type = *logical_type->physical_type(database).first;
switch (type.descriptor)
const ccc::ast::Node& physical_type = *logical_type->physical_type(database).first;
switch (physical_type.descriptor)
{
case ccc::ast::ARRAY:
{
const ccc::ast::Array& array = physical_type.as<ccc::ast::Array>();
const ccc::ast::Node& element_type = *array.element_type->physical_type(database).first;
QLineEdit* line_edit = qobject_cast<QLineEdit*>(editor);
if (array.element_count > 0 &&
element_type.name == "char" &&
node->location.type == SymbolTreeLocation::MEMORY &&
line_edit)
{
value = line_edit->text();
}
break;
}
case ccc::ast::BUILTIN:
{
const ccc::ast::BuiltIn& builtin = type.as<ccc::ast::BuiltIn>();
const ccc::ast::BuiltIn& builtin = physical_type.as<ccc::ast::BuiltIn>();
switch (builtin.bclass)
{
+60 -10
View File
@@ -67,7 +67,7 @@ bool SymbolTreeNode::writeToVM(
if (logical_type)
{
const ccc::ast::Node& physical_type = *logical_type->physical_type(database).first;
writeValueFromVariant(m_value, physical_type, cpu);
writeValueFromVariant(m_value, physical_type, cpu, database);
}
data_changed |= updateDisplayString(cpu, database, display_options);
@@ -76,10 +76,29 @@ bool SymbolTreeNode::writeToVM(
return data_changed;
}
QVariant SymbolTreeNode::readValueAsVariant(const ccc::ast::Node& physical_type, DebugInterface& cpu, const ccc::SymbolDatabase& database) const
QVariant SymbolTreeNode::readValueAsVariant(
const ccc::ast::Node& physical_type,
DebugInterface& cpu,
const ccc::SymbolDatabase& database) const
{
switch (physical_type.descriptor)
{
case ccc::ast::ARRAY:
{
const ccc::ast::Array& array = physical_type.as<ccc::ast::Array>();
const ccc::ast::Node& element_type = *array.element_type->physical_type(database).first;
if (array.element_count > 0 &&
element_type.name == "char" &&
location.type == SymbolTreeLocation::MEMORY)
{
std::optional<std::string> string = cpu.ReadString(location.address, 256);
if (string.has_value())
return QString::fromStdString(*string);
}
break;
}
case ccc::ast::BUILTIN:
{
const ccc::ast::BuiltIn& builtIn = physical_type.as<ccc::ast::BuiltIn>();
@@ -134,10 +153,36 @@ QVariant SymbolTreeNode::readValueAsVariant(const ccc::ast::Node& physical_type,
return QVariant();
}
bool SymbolTreeNode::writeValueFromVariant(QVariant value, const ccc::ast::Node& physical_type, DebugInterface& cpu) const
bool SymbolTreeNode::writeValueFromVariant(
QVariant value,
const ccc::ast::Node& physical_type,
DebugInterface& cpu,
const ccc::SymbolDatabase& database) const
{
if (value.isNull())
return false;
switch (physical_type.descriptor)
{
case ccc::ast::ARRAY:
{
const ccc::ast::Array& array = physical_type.as<ccc::ast::Array>();
const ccc::ast::Node& element_type = *array.element_type->physical_type(database).first;
if (array.element_count > 0 &&
element_type.name == "char" &&
location.type == SymbolTreeLocation::MEMORY)
{
QByteArray byte_array = value.toString().toLatin1();
std::string_view view(
byte_array.data(),
std::min(static_cast<s32>(byte_array.size()), array.element_count - 1));
cpu.WriteString(location.address, view);
break;
}
return false;
}
case ccc::ast::BUILTIN:
{
const ccc::ast::BuiltIn& built_in = physical_type.as<ccc::ast::BuiltIn>();
@@ -191,6 +236,7 @@ bool SymbolTreeNode::writeValueFromVariant(QVariant value, const ccc::ast::Node&
return false;
}
}
break;
}
case ccc::ast::ENUM:
@@ -266,11 +312,14 @@ QString SymbolTreeNode::generateDisplayString(
const ccc::ast::Array& array = physical_type.as<ccc::ast::Array>();
const ccc::ast::Node& element_type = *array.element_type->physical_type(database).first;
if (element_type.name == "char" && location.type == SymbolTreeLocation::MEMORY)
if (array.element_count > 0 &&
element_type.name == "char" &&
location.type == SymbolTreeLocation::MEMORY)
{
char* string = cpu.stringFromPointer(location.address);
if (string)
return QString("\"%1\"").arg(string);
std::optional<std::string> string = cpu.ReadString(
location.address, 256, MemoryInterface::ALLOW_LONG_STRINGS);
if (string.has_value())
return QString("\"%1\"").arg(*string);
}
QString result;
@@ -412,9 +461,10 @@ QString SymbolTreeNode::generateDisplayString(
if (pointer_or_reference.is_pointer && value_type.name == "char")
{
const char* string = cpu.stringFromPointer(address);
if (string)
result += QString(" \"%1\"").arg(string);
std::optional<std::string> string = cpu.ReadString(
address, 256, MemoryInterface::ALLOW_LONG_STRINGS);
if (string.has_value())
result += QString(" \"%1\"").arg(*string);
}
else if (depth == 0)
{
+11 -2
View File
@@ -62,11 +62,20 @@ public:
const ccc::SymbolDatabase& database,
const SymbolTreeDisplayOptions& display_options);
QVariant readValueAsVariant(const ccc::ast::Node& physical_type, DebugInterface& cpu, const ccc::SymbolDatabase& database) const;
bool writeValueFromVariant(QVariant value, const ccc::ast::Node& physical_type, DebugInterface& cpu) const;
QVariant readValueAsVariant(
const ccc::ast::Node& physical_type,
DebugInterface& cpu,
const ccc::SymbolDatabase& database) const;
bool writeValueFromVariant(
QVariant value,
const ccc::ast::Node& physical_type,
DebugInterface& cpu,
const ccc::SymbolDatabase& database) const;
bool updateDisplayString(
DebugInterface& cpu, const ccc::SymbolDatabase& database, const SymbolTreeDisplayOptions& display);
QString generateDisplayString(
const ccc::ast::Node& physical_type,
DebugInterface& cpu,
+29 -4
View File
@@ -73,9 +73,10 @@ const char* GameListModel::getColumnName(const Column col)
return s_column_names[static_cast<int>(col)];
}
GameListModel::GameListModel(const float cover_scale, const bool show_cover_titles, const qreal dpr, QObject* parent /* = nullptr */)
GameListModel::GameListModel(const float cover_scale, const bool show_cover_titles, bool show_full_cover_titles, const qreal dpr, QObject* parent /* = nullptr */)
: QAbstractTableModel(parent)
, m_show_titles_for_covers(show_cover_titles)
, m_show_full_titles_for_covers(show_full_cover_titles)
, m_dpr{dpr}
{
loadSettings();
@@ -315,9 +316,33 @@ QVariant GameListModel::data(const QModelIndex& index, const int role) const
switch (index.column())
{
case Column_Cover:
return QSize(static_cast<int>(static_cast<float>(SIZE_HINT_WIDTH) * m_cover_scale),
static_cast<int>(static_cast<float>(m_show_titles_for_covers ? SIZE_HINT_HEIGHT_TITLES : SIZE_HINT_HEIGHT) * m_cover_scale));
{
const int cover_width = static_cast<int>(static_cast<float>(SIZE_HINT_WIDTH) * m_cover_scale);
const int cover_height = static_cast<int>(static_cast<float>(SIZE_HINT_HEIGHT) * m_cover_scale);
if (m_show_full_titles_for_covers && m_show_titles_for_covers)
{
// Find height needed for the longest title at the current font/width
const int text_width = static_cast<int>(static_cast<float>(COVER_ART_WIDTH) * m_cover_scale);
QFont font;
font.setPointSizeF(20.0f * m_cover_scale);
const QFontMetrics fm(font);
int max_text_height = fm.height();
const auto lock = GameList::GetLock();
const u32 count = GameList::GetEntryCount();
for (u32 i = 0; i < count; i++)
{
const GameList::Entry* entry = GameList::GetEntryByIndex(i);
if (!entry) continue;
const QString title = QString::fromStdString(entry->GetTitle(m_prefer_english_titles));
const QRect bound = fm.boundingRect(QRect(0, 0, text_width, 0),
Qt::TextWordWrap | Qt::AlignHCenter, title);
max_text_height = std::max(max_text_height, bound.height());
}
return QSize(cover_width, cover_height + max_text_height);
}
return QSize(cover_width, static_cast<int>(static_cast<float>(m_show_titles_for_covers ? SIZE_HINT_HEIGHT_TITLES : SIZE_HINT_HEIGHT) * m_cover_scale));
}
default:
return QVariant();
}
@@ -354,7 +379,7 @@ bool GameListModel::titlesLessThan(const int left_row, const int right_row) cons
const GameList::Entry* left = GameList::GetEntryByIndex(left_row);
const GameList::Entry* right = GameList::GetEntryByIndex(right_row);
return QtHost::LocaleSensitiveCompare(QString::fromStdString(left->GetTitleSort(m_prefer_english_titles)),
QString::fromStdString(right->GetTitleSort(m_prefer_english_titles))) < 0;
QString::fromStdString(right->GetTitleSort(m_prefer_english_titles))) < 0;
}
bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& right_index, const int column) const
+5 -1
View File
@@ -43,7 +43,7 @@ public:
static QIcon getIconForType(GameList::EntryType type);
static QIcon getIconForRegion(GameList::Region region);
GameListModel(float cover_scale, bool show_cover_titles, qreal dpr, QObject* parent = nullptr);
GameListModel(float cover_scale, bool show_cover_titles, bool show_full_cover_titles, qreal dpr, QObject* parent = nullptr);
~GameListModel();
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
@@ -63,6 +63,9 @@ public:
bool getShowCoverTitles() const { return m_show_titles_for_covers; }
void setShowCoverTitles(bool enabled) { m_show_titles_for_covers = enabled; }
bool getShowFullCoverTitles() const { return m_show_full_titles_for_covers; }
void setShowFullCoverTitles(bool enabled) { m_show_full_titles_for_covers = enabled; }
float getCoverScale() const { return m_cover_scale; }
void setCoverScale(float scale);
int getCoverArtWidth() const;
@@ -89,6 +92,7 @@ private:
float m_cover_scale = 0.0f;
std::atomic<u32> m_cover_scale_counter{0};
bool m_show_titles_for_covers = false;
bool m_show_full_titles_for_covers = false;
bool m_prefer_english_titles = false;
std::array<QString, Column_Count> m_column_display_names;
+133 -32
View File
@@ -22,7 +22,10 @@
#include <QtCore/QSortFilterProxyModel>
#include <QtCore/QDir>
#include <QtCore/QString>
#include <QtGui/QColor>
#include <QtGui/QImage>
#include <QtGui/QPainter>
#include <QtGui/QPalette>
#include <QtGui/QPixmap>
#include <QtGui/QPixmapCache>
#include <QtGui/QWheelEvent>
@@ -191,6 +194,29 @@ namespace
painter->drawPixmap(rect.topLeft() + icon_top_left, highlighted_icon);
}
// Recolor the icon based on the custom background color
else if (index.column() == GameListModel::Column_Type)
{
// Fetch pixmap from cache or construct a new one.
const QColor color = option.palette.color(QPalette::Text);
const QString key = QString::fromStdString(fmt::format("type-{:016X}-{:08X}", icon.cacheKey(), color.rgba()));
QPixmap tinted_icon;
if (!QPixmapCache::find(key, &tinted_icon))
{
QImage img = icon.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
QPainter tinted_painter(&img);
tinted_painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
tinted_painter.fillRect(0, 0, img.width(), img.height(), color);
tinted_painter.end();
tinted_icon = QPixmap(QPixmap::fromImage(img));
QPixmapCache::insert(key, tinted_icon);
}
painter->drawPixmap(rect.topLeft() + icon_top_left, tinted_icon);
}
else
{
painter->drawPixmap(rect.topLeft() + icon_top_left, icon);
@@ -213,7 +239,8 @@ void GameListWidget::initialize()
{
const float cover_scale = Host::GetBaseFloatSettingValue("UI", "GameListCoverArtScale", 0.45f);
const bool show_cover_titles = Host::GetBaseBoolSettingValue("UI", "GameListShowCoverTitles", true);
m_model = new GameListModel(cover_scale, show_cover_titles, devicePixelRatioF(), this);
const bool show_full_cover_titles = Host::GetBaseBoolSettingValue("UI", "GameListShowFullCoverTitles", true);
m_model = new GameListModel(cover_scale, show_cover_titles, show_full_cover_titles, devicePixelRatioF(), this);
m_model->updateCacheSize(width(), height());
m_sort_model = new GameListSortModel(m_model);
@@ -242,6 +269,7 @@ void GameListWidget::initialize()
connect(m_ui.viewGameGrid, &QPushButton::clicked, this, &GameListWidget::showGameGrid);
connect(m_ui.gridScale, &QSlider::valueChanged, this, &GameListWidget::gridIntScale);
connect(m_ui.viewGridTitles, &QPushButton::toggled, this, &GameListWidget::setShowCoverTitles);
connect(m_ui.viewFullGridTitles, &QPushButton::toggled, this, &GameListWidget::setShowFullCoverTitles);
connect(m_ui.filterType, &QComboBox::currentIndexChanged, this, [this](int index) {
m_sort_model->setFilterType((index == 0) ? GameList::EntryType::Count : static_cast<GameList::EntryType>(index - 1));
});
@@ -322,6 +350,7 @@ void GameListWidget::initialize()
m_list_view->setFrameStyle(QFrame::NoFrame);
m_list_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
m_list_view->verticalScrollBar()->setSingleStep(15);
m_list_view->setWordWrap(show_full_cover_titles);
onCoverScaleChanged();
connect(m_list_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
@@ -381,8 +410,14 @@ void GameListWidget::setCustomBackground()
delete m_background_movie;
m_background_movie = nullptr;
}
// Cache all frames for small images so loops don't keep re-decoding
else if (const s64 file_size = FileSystem::GetPathFileSize(path.c_str()); file_size > 0 && file_size < 64 * 1024 * 1024)
m_background_movie->setCacheMode(QMovie::CacheAll);
}
// Invalidate frame cache so the next animated frame triggers full reprocessing
m_background_last_size = QSize();
// If there is no valid background then reset fallback to default UI state
if (!m_background_movie)
{
@@ -391,6 +426,11 @@ void GameListWidget::setCustomBackground()
m_table_view->viewport()->setAutoFillBackground(true);
m_list_view->viewport()->setAutoFillBackground(true);
m_ui.stack->setPalette(QPalette());
m_background_text_color = QColor();
m_empty_widget->setPalette(QPalette());
m_empty_widget->setAutoFillBackground(false);
m_ui.stack->update();
m_table_view->setAlternatingRowColors(true);
return;
@@ -415,45 +455,79 @@ void GameListWidget::setCustomBackground()
m_background_opacity = Host::GetBaseFloatSettingValue("UI", "GameListBackgroundOpacity", 100.0f);
// Selected Custom background is valid, connect the signals and start animation in gamelist
connect(m_background_movie, &QMovie::frameChanged, this, &GameListWidget::processBackgroundFrames, Qt::UniqueConnection);
connect(m_background_movie, &QMovie::frameChanged, this, &GameListWidget::processBackgroundFrames);
m_ui.stack->setAutoFillBackground(false);
m_table_view->viewport()->setAutoFillBackground(false);
m_list_view->viewport()->setAutoFillBackground(false);
updateCustomBackgroundState(true);
m_background_movie->start();
updateCustomBackgroundState();
m_table_view->setAlternatingRowColors(false);
processBackgroundFrames();
}
void GameListWidget::updateCustomBackgroundState(const bool force_start)
void GameListWidget::updateCustomBackgroundState()
{
if (m_background_movie && m_background_movie->isValid())
{
if ((isVisible() && (isActiveWindow() || force_start)) && qGuiApp->applicationState() == Qt::ApplicationActive)
m_background_movie->setPaused(false);
else
m_background_movie->setPaused(true);
}
m_background_movie->setPaused(!(isVisible() && qGuiApp->applicationState() == Qt::ApplicationActive));
}
void GameListWidget::processBackgroundFrames()
{
if (m_background_movie && m_background_movie->isValid() && isVisible())
{
const int widget_width = m_ui.stack->width();
const int widget_height = m_ui.stack->height();
if (!m_background_movie || !m_background_movie->isValid() || !isVisible())
return;
if (widget_width <= 0 || widget_height <= 0)
return;
const QSize widget_size(m_ui.stack->width(), m_ui.stack->height());
if (widget_size.isEmpty())
return;
QPixmap pm = m_background_movie->currentPixmap();
const qreal dpr = devicePixelRatioF();
const int frame_number = m_background_movie->currentFrameNumber();
const qreal dpr = devicePixelRatioF();
QtUtils::resizeAndScalePixmap(&pm, widget_width, widget_height, dpr, m_background_scaling, m_background_opacity);
if (frame_number == m_background_last_frame && widget_size == m_background_last_size && qFuzzyCompare(dpr, m_background_last_dpr))
return;
m_background_pixmap = std::move(pm);
m_ui.stack->update();
}
QPixmap pm = m_background_movie->currentPixmap();
updateBackgroundTextColor(pm);
QtUtils::resizeAndScalePixmap(&pm, widget_size.width(), widget_size.height(), dpr, m_background_scaling, m_background_opacity);
m_background_pixmap = std::move(pm);
m_background_last_frame = frame_number;
m_background_last_size = widget_size;
m_background_last_dpr = dpr;
m_ui.stack->update();
}
void GameListWidget::updateBackgroundTextColor(const QPixmap& frame)
{
if (frame.isNull())
return;
const QImage sampled = frame.scaled(32, 32, Qt::IgnoreAspectRatio, Qt::FastTransformation).toImage();
const QColor average = sampled.scaled(1, 1, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).pixelColor(0, 0);
const QColor base = qApp->palette().color(QPalette::Base);
const qreal coverage = average.alphaF() * std::clamp(m_background_opacity / 100.0f, 0.0f, 1.0f);
const qreal brightness = qGray(average.rgb()) * coverage + qGray(base.rgb()) * (1.0 - coverage);
const QColor text_color = (brightness > 127.5) ? Qt::black : Qt::white;
if (m_background_text_color == text_color)
return;
m_background_text_color = text_color;
QColor highlight_color = qApp->palette().color(QPalette::Highlight);
highlight_color.setAlpha(128);
const QColor empty_backdrop_color = (text_color == Qt::black) ? QColor(255, 255, 255, 128) : QColor(0, 0, 0, 128);
QPalette palette;
palette.setColor(QPalette::Text, text_color);
palette.setColor(QPalette::WindowText, text_color);
palette.setColor(QPalette::Highlight, highlight_color);
m_ui.stack->setPalette(palette);
QPalette empty_palette;
empty_palette.setColor(QPalette::Window, empty_backdrop_color);
m_empty_widget->setPalette(empty_palette);
m_empty_widget->setAutoFillBackground(true);
}
bool GameListWidget::isShowingGameList() const
@@ -471,6 +545,11 @@ bool GameListWidget::getShowGridCoverTitles() const
return m_model->getShowCoverTitles();
}
bool GameListWidget::getShowGridFullCoverTitles() const
{
return m_model->getShowFullCoverTitles();
}
void GameListWidget::refresh(bool invalidate_cache, bool popup_on_error)
{
cancelRefresh();
@@ -499,6 +578,8 @@ void GameListWidget::cancelRefresh()
void GameListWidget::reloadThemeSpecificImages()
{
m_model->reloadThemeSpecificImages();
m_background_last_size = QSize();
processBackgroundFrames();
}
void GameListWidget::onRefreshProgress(const QString& status, int current, int total)
@@ -654,6 +735,9 @@ void GameListWidget::refreshGridCovers()
void GameListWidget::showGameList()
{
Host::SetBaseBoolSettingValue("UI", "GameListGridView", false);
Host::CommitBaseSettingChanges();
if (m_ui.stack->currentIndex() == 0 || m_model->rowCount() == 0)
{
// We can click the toolbar multiple times, so keep it correct.
@@ -661,8 +745,6 @@ void GameListWidget::showGameList()
return;
}
Host::SetBaseBoolSettingValue("UI", "GameListGridView", false);
Host::CommitBaseSettingChanges();
m_ui.stack->setCurrentIndex(0);
setFocusProxy(m_ui.stack->currentWidget());
resizeTableViewColumnsToFit();
@@ -672,6 +754,9 @@ void GameListWidget::showGameList()
void GameListWidget::showGameGrid()
{
Host::SetBaseBoolSettingValue("UI", "GameListGridView", true);
Host::CommitBaseSettingChanges();
if (m_ui.stack->currentIndex() == 1 || m_model->rowCount() == 0)
{
// We can click the toolbar multiple times, so keep it correct.
@@ -679,8 +764,6 @@ void GameListWidget::showGameGrid()
return;
}
Host::SetBaseBoolSettingValue("UI", "GameListGridView", true);
Host::CommitBaseSettingChanges();
m_ui.stack->setCurrentIndex(1);
setFocusProxy(m_ui.stack->currentWidget());
updateToolbar();
@@ -701,9 +784,24 @@ void GameListWidget::setShowCoverTitles(bool enabled)
emit layoutChange();
}
void GameListWidget::setShowFullCoverTitles(bool enabled)
{
if (m_model->getShowFullCoverTitles() == enabled)
return;
Host::SetBaseBoolSettingValue("UI", "GameListShowFullCoverTitles", enabled);
Host::CommitBaseSettingChanges();
m_model->setShowFullCoverTitles(enabled);
m_list_view->setWordWrap(enabled);
if (isShowingGameGrid())
m_model->refresh();
updateToolbar();
emit layoutChange();
}
void GameListWidget::updateToolbar()
{
const bool grid_view = isShowingGameGrid();
const bool grid_view = Host::GetBaseBoolSettingValue("UI", "GameListGridView", false);
{
QSignalBlocker sb(m_ui.viewGameGrid);
m_ui.viewGameGrid->setChecked(grid_view);
@@ -716,12 +814,17 @@ void GameListWidget::updateToolbar()
QSignalBlocker sb(m_ui.viewGridTitles);
m_ui.viewGridTitles->setChecked(m_model->getShowCoverTitles());
}
{
QSignalBlocker sb(m_ui.viewFullGridTitles);
m_ui.viewFullGridTitles->setChecked(m_model->getShowFullCoverTitles());
}
{
QSignalBlocker sb(m_ui.gridScale);
m_ui.gridScale->setValue(static_cast<int>(m_model->getCoverScale() * 100.0f));
}
m_ui.viewGridTitles->setEnabled(grid_view);
m_ui.viewFullGridTitles->setEnabled(grid_view && m_model->getShowCoverTitles());
m_ui.gridScale->setEnabled(grid_view);
}
@@ -729,6 +832,7 @@ void GameListWidget::showEvent(QShowEvent* event)
{
QWidget::showEvent(event);
updateCustomBackgroundState();
processBackgroundFrames();
}
void GameListWidget::hideEvent(QHideEvent* event)
@@ -765,11 +869,8 @@ bool GameListWidget::eventFilter(QObject* watched, QEvent* event)
if (!m_background_pixmap.isNull())
{
QPainter painter(m_ui.stack);
const auto* paint_event = static_cast<QPaintEvent*>(event);
painter.save();
painter.setClipRect(paint_event->rect());
painter.drawTiledPixmap(m_ui.stack->rect(), m_background_pixmap);
painter.restore();
painter.setClipRect(static_cast<QPaintEvent*>(event)->rect());
painter.drawPixmap(0, 0, m_background_pixmap);
return true;
}
}
+9 -1
View File
@@ -9,6 +9,7 @@
#include "pcsx2/GameList.h"
#include <QtGui/QColor>
#include <QtGui/QMovie>
#include <QtGui/QPixmap>
#include <QtWidgets/QListView>
@@ -53,12 +54,14 @@ public:
void cancelRefresh();
void reloadThemeSpecificImages();
void setCustomBackground();
void updateCustomBackgroundState(const bool force_start = false);
void updateCustomBackgroundState();
void processBackgroundFrames();
void updateBackgroundTextColor(const QPixmap& frame);
bool isShowingGameList() const;
bool isShowingGameGrid() const;
bool getShowGridCoverTitles() const;
bool getShowGridFullCoverTitles() const;
std::optional<GameList::Entry> getSelectedEntry() const;
@@ -93,6 +96,7 @@ public Q_SLOTS:
void showGameList();
void showGameGrid();
void setShowCoverTitles(bool enabled);
void setShowFullCoverTitles(bool enabled);
void gridZoomIn();
void gridZoomOut();
void gridIntScale(int int_scale);
@@ -128,6 +132,10 @@ private:
QMovie* m_background_movie = nullptr;
QPixmap m_background_pixmap;
QColor m_background_text_color;
QtUtils::ScalingMode m_background_scaling = QtUtils::ScalingMode::Fit;
float m_background_opacity = 100.0f;
int m_background_last_frame = -1;
QSize m_background_last_size;
qreal m_background_last_dpr = 0.0;
};
+26
View File
@@ -120,6 +120,31 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="viewFullGridTitles">
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Show Full Titles</string>
</property>
<property name="text">
<string>Show Full Titles</string>
</property>
<property name="icon">
<iconset theme="price-tag-2-line"/>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="gridScale">
<property name="minimumSize">
@@ -218,6 +243,7 @@
<tabstop>viewGameList</tabstop>
<tabstop>viewGameGrid</tabstop>
<tabstop>viewGridTitles</tabstop>
<tabstop>viewFullGridTitles</tabstop>
<tabstop>gridScale</tabstop>
<tabstop>filterType</tabstop>
<tabstop>filterRegion</tabstop>
+309 -64
View File
@@ -36,6 +36,9 @@
#include "pcsx2/ImGui/FullscreenUI.h"
#include "pcsx2/MTGS.h"
#include "pcsx2/PerformanceMetrics.h"
#include "pcsx2/VMManager.h"
#include "pcsx2/ImGui/ImGuiOverlays.h"
#include "pcsx2/SPU2/spu2.h"
#include "pcsx2/Recording/InputRecording.h"
#include "pcsx2/Recording/InputRecordingControls.h"
#include "pcsx2/SaveState.h"
@@ -54,8 +57,11 @@
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QProgressBar>
#include <QtWidgets/QSlider>
#include <QtWidgets/QStyle>
#include <QtWidgets/QStyleFactory>
#include <QtWidgets/QWidgetAction>
#include <QtWidgets/QHBoxLayout>
#ifdef _WIN32
#include "common/RedtapeWindows.h"
@@ -147,6 +153,14 @@ void MainWindow::initialize()
switchToGameListView();
updateWindowTitle();
updateGameDependentActions();
updateEmulationActions(false, s_vm_valid, false);
updateStatusBarWidgetVisibility();
if (s_vm_paused)
{
m_ui.actionPause->setChecked(true);
m_ui.actionToolbarPause->setChecked(true);
}
#ifdef _WIN32
registerForDeviceNotifications();
@@ -185,6 +199,7 @@ void MainWindow::setupAdditionalUi()
{
makeIconsMasks(menuBar());
updateAdvancedSettingsVisibility();
setupStatusBarWidgets();
const bool toolbar_visible = Host::GetBaseBoolSettingValue("UI", "ShowToolbar", false);
m_ui.actionViewToolbar->setChecked(toolbar_visible);
@@ -195,58 +210,6 @@ void MainWindow::setupAdditionalUi()
m_ui.toolBar->setMovable(!toolbars_locked);
m_ui.toolBar->setContextMenuPolicy(Qt::PreventContextMenu);
const bool status_bar_visible = Host::GetBaseBoolSettingValue("UI", "ShowStatusBar", true);
m_ui.actionViewStatusBar->setChecked(status_bar_visible);
m_ui.statusBar->setVisible(status_bar_visible);
const bool show_game_grid = Host::GetBaseBoolSettingValue("UI", "GameListGridView", false);
updateGameGridActions(show_game_grid);
m_game_list_widget = new GameListWidget(getContentParent());
m_game_list_widget->initialize();
m_ui.actionGridViewShowTitles->setChecked(m_game_list_widget->getShowGridCoverTitles());
m_ui.mainContainer->addWidget(m_game_list_widget);
m_status_progress_widget = new QProgressBar(m_ui.statusBar);
m_status_progress_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
m_status_progress_widget->setFixedSize(140, 16);
m_status_progress_widget->setMinimum(0);
m_status_progress_widget->setMaximum(100);
m_status_progress_widget->hide();
m_status_verbose_widget = new QLabel(m_ui.statusBar);
m_status_verbose_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_status_verbose_widget->setFixedHeight(16);
m_status_verbose_widget->hide();
m_status_renderer_widget = new QLabel(m_ui.statusBar);
m_status_renderer_widget->setFixedHeight(16);
m_status_renderer_widget->setFixedSize(65, 16);
m_status_renderer_widget->hide();
m_status_resolution_widget = new QLabel(m_ui.statusBar);
m_status_resolution_widget->setFixedHeight(16);
m_status_resolution_widget->setFixedSize(75, 16);
m_status_resolution_widget->hide();
m_status_fps_widget = new QLabel(m_ui.statusBar);
m_status_fps_widget->setFixedHeight(16);
m_status_fps_widget->setMinimumWidth(60);
m_status_fps_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
m_status_fps_widget->hide();
m_status_vps_widget = new QLabel(m_ui.statusBar);
m_status_vps_widget->setFixedHeight(16);
m_status_vps_widget->setMinimumWidth(60);
m_status_vps_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
m_status_vps_widget->hide();
m_status_speed_widget = new QLabel(m_ui.statusBar);
m_status_speed_widget->setFixedHeight(16);
m_status_speed_widget->setMinimumWidth(130);
m_status_speed_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
m_status_speed_widget->hide();
m_settings_toolbar_menu = new QMenu(m_ui.toolBar);
m_settings_toolbar_menu->addAction(m_ui.actionSettings);
m_settings_toolbar_menu->addAction(m_ui.actionViewGameProperties);
@@ -257,6 +220,16 @@ void MainWindow::setupAdditionalUi()
connect(action, &QAction::triggered, [scale]() { g_emu_thread->requestDisplaySize(static_cast<float>(scale)); });
}
const bool show_game_grid = Host::GetBaseBoolSettingValue("UI", "GameListGridView", false);
const bool show_grid_cover_titles = Host::GetBaseBoolSettingValue("UI", "ShowGridCoverTitles", false);
updateGameGridActions(show_game_grid, show_grid_cover_titles);
m_game_list_widget = new GameListWidget(getContentParent());
m_game_list_widget->initialize();
m_ui.actionGridViewShowTitles->setChecked(m_game_list_widget->getShowGridCoverTitles());
m_ui.actionGridViewShowFullTitles->setChecked(m_game_list_widget->getShowGridFullCoverTitles());
m_ui.mainContainer->addWidget(m_game_list_widget);
updateEmulationActions(false, false, false);
updateDisplayRelatedActions(false, false, false);
@@ -292,6 +265,216 @@ void MainWindow::setupAdditionalUi()
#endif
}
void MainWindow::setupStatusBarWidgets()
{
const bool status_bar_visible = Host::GetBaseBoolSettingValue("UI", "ShowStatusBar", true);
m_ui.actionViewStatusBar->setChecked(status_bar_visible);
m_ui.statusBar->setVisible(status_bar_visible);
m_status_progress_widget = new QProgressBar(m_ui.statusBar);
m_status_progress_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
m_status_progress_widget->setFixedSize(140, 16);
m_status_progress_widget->setMinimum(0);
m_status_progress_widget->setMaximum(100);
m_status_progress_widget->hide();
m_status_verbose_widget = new QLabel(m_ui.statusBar);
m_status_verbose_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_status_verbose_widget->setContentsMargins(10, 0, 10, 0);
m_status_verbose_widget->setFixedHeight(20);
m_status_verbose_widget->setMinimumWidth(20);
m_status_verbose_widget->hide();
m_status_renderer_widget = new QLabel(m_ui.statusBar);
m_status_renderer_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
m_status_renderer_widget->setContentsMargins(10, 0, 10, 0);
m_status_renderer_widget->setAlignment(Qt::AlignCenter);
m_status_renderer_widget->setFixedHeight(20);
m_status_renderer_widget->hide();
m_status_resolution_widget = new QLabel(m_ui.statusBar);
m_status_resolution_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
m_status_resolution_widget->setContentsMargins(10, 0, 10, 0);
m_status_resolution_widget->setAlignment(Qt::AlignCenter);
m_status_resolution_widget->setFixedHeight(20);
m_status_resolution_widget->hide();
m_status_volume_widget = new QToolButton(m_ui.statusBar);
m_status_volume_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
m_status_volume_widget->setContentsMargins(10, 0, 10, 0);
m_status_volume_widget->setAutoRaise(true);
m_status_volume_widget->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
m_status_volume_widget->setIcon(QIcon::fromTheme(QStringLiteral("volume-up-line")));
m_status_volume_widget->setPopupMode(QToolButton::InstantPopup);
m_status_volume_widget->setFixedHeight(20);
m_status_volume_menu = new QMenu(m_status_volume_widget);
m_status_volume_per_game_action = new QAction(tr("Adjust Per-Game"), m_status_volume_menu);
m_status_volume_per_game_action->setCheckable(true);
connect(m_status_volume_menu, &QMenu::aboutToShow, this, [this]() {
auto lock = Host::GetSettingsLock();
SettingsInterface* game_layer = Host::Internal::GetGameSettingsLayer();
m_status_volume_per_game_action->setEnabled(game_layer != nullptr && QtHost::IsVMValid());
m_status_volume_per_game_action->setChecked(game_layer &&
(game_layer->ContainsValue("SPU2/Output", "StandardVolume") || game_layer->ContainsValue("SPU2/Output", "OutputMuted")));
});
connect(m_status_volume_per_game_action, &QAction::triggered, this, [this](bool checked) {
m_status_volume_slider_applied = true;
applyStatusBarVolumeChanges(std::nullopt, false, checked);
});
m_status_volume_toggle_mute_action = new QAction(tr("Toggle Mute"), m_status_volume_menu);
m_status_volume_toggle_mute_action->setIcon(QIcon::fromTheme(QStringLiteral("volume-mute-line")));
connect(m_status_volume_toggle_mute_action, &QAction::triggered, this, [this]() {
m_status_volume_slider_applied = true;
applyStatusBarVolumeChanges(std::nullopt, true, std::nullopt);
});
m_status_volume_menu->addAction(m_status_volume_per_game_action);
m_status_volume_menu->addAction(m_status_volume_toggle_mute_action);
m_status_volume_menu->addSeparator();
m_status_volume_slider = new QSlider(Qt::Horizontal, m_status_volume_menu);
m_status_volume_slider->setRange(0, 100);
m_status_volume_slider->setFixedWidth(120);
m_status_volume_slider->setValue(Host::GetIntSettingValue("SPU2/Output", "StandardVolume", 100));
connect(m_status_volume_slider, &QSlider::valueChanged, this, [this](int value) {
Host::RunOnCPUThread([value]() {
if (!VMManager::HasValidVM())
return;
EmuConfig.SPU2.StandardVolume = static_cast<u32>(value);
SPU2::SetOutputVolume(static_cast<u32>(value));
});
if (m_status_volume_slider->isSliderDown())
setStatusVolumeText(m_status_volume_muted ? tr("Volume: Muted") : tr("Volume: %1%").arg(value), value, m_status_volume_muted);
});
connect(m_status_volume_slider, &QSlider::sliderReleased, this, [this]() {
m_status_volume_slider_applied = true;
applyStatusBarVolumeChanges(m_status_volume_slider->value(), false);
});
connect(m_status_volume_menu, &QMenu::aboutToHide, this, [this]() {
if (!m_status_volume_slider_applied)
applyStatusBarVolumeChanges(m_status_volume_slider->value(), false);
m_status_volume_slider_applied = false;
});
QWidget* container = new QWidget(m_status_volume_menu);
QHBoxLayout* layout = new QHBoxLayout(container);
layout->setContentsMargins(8, 4, 8, 4);
layout->addWidget(m_status_volume_slider);
QWidgetAction* slider_action = new QWidgetAction(m_status_volume_menu);
slider_action->setDefaultWidget(container);
m_status_volume_menu->addAction(slider_action);
m_status_volume_widget->setMenu(m_status_volume_menu);
m_status_volume_widget->hide();
m_status_speed_widget = new QToolButton(m_ui.statusBar);
m_status_speed_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
m_status_speed_widget->setContentsMargins(10, 0, 10, 0);
m_status_speed_widget->setAutoRaise(true);
m_status_speed_widget->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
m_status_speed_widget->setPopupMode(QToolButton::InstantPopup);
m_status_speed_widget->setFixedHeight(20);
m_status_speed_widget->hide();
m_status_speed_menu = new QMenu(m_status_speed_widget);
m_status_speed_menu->addAction(tr("Unlimited"), []() { Host::RunOnCPUThread([]() { VMManager::SetLimiterMode(LimiterModeType::Unlimited); }); });
m_status_speed_menu->addAction(tr("Turbo"), []() { Host::RunOnCPUThread([]() { VMManager::SetLimiterMode(LimiterModeType::Turbo); }); });
m_status_speed_menu->addAction(tr("Slow-Motion"), []() { Host::RunOnCPUThread([]() { VMManager::SetLimiterMode(LimiterModeType::Slomo); }); });
m_status_speed_menu->addAction(tr("Normal"), []() { Host::RunOnCPUThread([]() { VMManager::SetLimiterMode(LimiterModeType::Nominal); }); });
m_status_speed_widget->setMenu(m_status_speed_menu);
m_status_speed_widget->hide();
m_status_gpu_widget = new QLabel(m_ui.statusBar);
m_status_gpu_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
m_status_gpu_widget->setContentsMargins(10, 0, 10, 0);
m_status_gpu_widget->setAlignment(Qt::AlignCenter);
m_status_gpu_widget->setFixedHeight(20);
m_status_gpu_widget->hide();
m_status_fps_widget = new QLabel(m_ui.statusBar);
m_status_fps_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
m_status_fps_widget->setContentsMargins(10, 0, 10, 0);
m_status_fps_widget->setAlignment(Qt::AlignCenter);
m_status_fps_widget->setFixedHeight(20);
m_status_fps_widget->hide();
m_status_vps_widget = new QLabel(m_ui.statusBar);
m_status_vps_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
m_status_vps_widget->setContentsMargins(10, 0, 10, 0);
m_status_vps_widget->setAlignment(Qt::AlignCenter);
m_status_vps_widget->setFixedHeight(20);
m_status_vps_widget->hide();
}
void MainWindow::applyStatusBarVolumeChanges(std::optional<int> volume, bool toggle_mute, std::optional<bool> override_per_game)
{
const bool use_per_game = override_per_game.value_or(m_status_volume_per_game_action->isChecked());
Host::RunOnCPUThread([this, volume, toggle_mute, use_per_game]() {
int target_vol = 100;
bool target_mute = false;
{
auto lock = Host::GetSettingsLock();
SettingsInterface* per_game_settings = Host::Internal::GetGameSettingsLayer();
SettingsInterface* global_settings = Host::Internal::GetBaseSettingsLayer();
SettingsInterface* active_setting = (use_per_game && per_game_settings) ? per_game_settings : global_settings;
if (active_setting)
{
if (!active_setting->GetIntValue("SPU2/Output", "StandardVolume", &target_vol) && global_settings)
global_settings->GetIntValue("SPU2/Output", "StandardVolume", &target_vol);
if (!active_setting->GetBoolValue("SPU2/Output", "OutputMuted", &target_mute) && global_settings)
global_settings->GetBoolValue("SPU2/Output", "OutputMuted", &target_mute);
}
target_vol = volume.value_or(target_vol);
if (toggle_mute)
target_mute = !(VMManager::HasValidVM() ? SPU2::IsOutputMuted() : target_mute);
if (active_setting)
{
active_setting->SetIntValue("SPU2/Output", "StandardVolume", target_vol);
active_setting->SetBoolValue("SPU2/Output", "OutputMuted", target_mute);
}
if (per_game_settings && active_setting == per_game_settings)
QtHost::SaveGameSettings(per_game_settings, true);
else
{
if (per_game_settings)
{
const bool had_per_game_volume =
per_game_settings->ContainsValue("SPU2/Output", "StandardVolume") ||
per_game_settings->ContainsValue("SPU2/Output", "OutputMuted");
per_game_settings->DeleteValue("SPU2/Output", "StandardVolume");
per_game_settings->DeleteValue("SPU2/Output", "OutputMuted");
if (had_per_game_volume)
QtHost::SaveGameSettings(per_game_settings, true);
}
Host::CommitBaseSettingChanges();
}
}
if (VMManager::HasValidVM())
{
EmuConfig.SPU2.StandardVolume = static_cast<u32>(target_vol);
EmuConfig.SPU2.OutputMuted = target_mute;
SPU2::SetOutputMuted(target_mute);
SPU2::SetOutputVolume(static_cast<u32>(target_vol));
}
QTimer::singleShot(0, this, [this, target_vol, target_mute]() {
setStatusVolumeText(target_mute ? tr("Volume: Muted") : tr("Volume: %1%").arg(target_vol), target_vol, target_mute);
});
});
}
void MainWindow::connectSignals()
{
connect(m_ui.actionStartFile, &QAction::triggered, this, &MainWindow::onStartFileActionTriggered);
@@ -362,6 +545,7 @@ void MainWindow::connectSignals()
connect(m_ui.actionOpenDataDirectory, &QAction::triggered, this, &MainWindow::onToolsOpenDataDirectoryTriggered);
connect(m_ui.actionCoverDownloader, &QAction::triggered, this, &MainWindow::onToolsCoverDownloaderTriggered);
connect(m_ui.actionGridViewShowTitles, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowCoverTitles);
connect(m_ui.actionGridViewShowFullTitles, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowFullCoverTitles);
connect(m_ui.actionGridViewZoomIn, &QAction::triggered, m_game_list_widget, [this]() {
if (isShowingGameList())
m_game_list_widget->gridZoomIn();
@@ -373,8 +557,10 @@ void MainWindow::connectSignals()
connect(m_ui.actionGridViewRefreshCovers, &QAction::triggered, m_game_list_widget, &GameListWidget::refreshGridCovers);
connect(m_game_list_widget, &GameListWidget::layoutChange, this, [this]() {
QSignalBlocker sb(m_ui.actionGridViewShowTitles);
QSignalBlocker sb2(m_ui.actionGridViewShowFullTitles);
m_ui.actionGridViewShowTitles->setChecked(m_game_list_widget->getShowGridCoverTitles());
updateGameGridActions(m_game_list_widget->isShowingGameGrid());
m_ui.actionGridViewShowFullTitles->setChecked(m_game_list_widget->getShowGridFullCoverTitles());
updateGameGridActions(m_game_list_widget->isShowingGameGrid(), m_game_list_widget->getShowGridCoverTitles());
});
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionViewStatusBarVerbose, "UI", "VerboseStatusBar", false);
@@ -454,8 +640,6 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
connect(thread, &EmuThread::onCaptureStopped, this, &MainWindow::onCaptureStopped);
connect(thread, &EmuThread::onAchievementsLoginRequested, this, &MainWindow::onAchievementsLoginRequested);
connect(thread, &EmuThread::onAchievementsHardcoreModeChanged, this, &MainWindow::onAchievementsHardcoreModeChanged);
connect(thread, &EmuThread::onCoverDownloaderOpenRequested, this, &MainWindow::onToolsCoverDownloaderTriggered);
connect(thread, &EmuThread::onCreateMemoryCardOpenRequested, this, &MainWindow::onCreateMemoryCardOpenRequested);
connect(m_ui.actionReset, &QAction::triggered, this, &MainWindow::requestReset);
connect(m_ui.actionPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
@@ -498,12 +682,11 @@ void MainWindow::createRendererSwitchMenu()
QString::fromUtf8(Pcsx2Config::GSOptions::GetRendererName(renderer)), switch_renderer_group);
action->setCheckable(true);
action->setChecked(current_renderer == renderer);
connect(action,
&QAction::triggered, [renderer] {
Host::SetBaseIntSettingValue("EmuCore/GS", "Renderer", static_cast<int>(renderer));
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
connect(action, &QAction::triggered, [renderer] {
Host::SetBaseIntSettingValue("EmuCore/GS", "Renderer", static_cast<int>(renderer));
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
m_ui.menuDebugSwitchRenderer->addActions(switch_renderer_group->actions());
@@ -550,6 +733,9 @@ void MainWindow::recreate()
g_main_window->updateEmulationActions(false, s_vm_valid, false);
g_main_window->onFullscreenUIStateChange(g_emu_thread->isRunningFullscreenUI());
}
if (s_vm_valid)
g_emu_thread->updatePerformanceMetrics(true);
}
void MainWindow::recreateSettings()
@@ -1021,13 +1207,15 @@ void MainWindow::updateDisplayRelatedActions(bool has_surface, bool render_to_ma
void MainWindow::updateStatusBarWidgetVisibility()
{
auto Update = [this](QWidget* widget, bool visible, int stretch) {
if (widget->isVisible() == visible)
return;
if (widget->isVisible())
{
m_ui.statusBar->removeWidget(widget);
widget->hide();
}
if (visible)
else
{
m_ui.statusBar->addPermanentWidget(widget, stretch);
widget->show();
@@ -1037,9 +1225,63 @@ void MainWindow::updateStatusBarWidgetVisibility()
Update(m_status_verbose_widget, s_vm_valid, 1);
Update(m_status_renderer_widget, s_vm_valid, 0);
Update(m_status_resolution_widget, s_vm_valid, 0);
Update(m_status_gpu_widget, s_vm_valid, 0);
Update(m_status_fps_widget, s_vm_valid, 0);
Update(m_status_vps_widget, s_vm_valid, 0);
Update(m_status_speed_widget, s_vm_valid, 0);
Update(m_status_volume_widget, s_vm_valid, 0);
}
void MainWindow::setStatusVerboseText(const QString& text)
{
m_status_verbose_widget->setText(text);
}
void MainWindow::setStatusRendererText(const QString& text)
{
m_status_renderer_widget->setText(text);
}
void MainWindow::setStatusResolutionText(const QString& text)
{
m_status_resolution_widget->setText(text);
}
void MainWindow::setStatusVolumeText(const QString& text, int volume, bool muted)
{
m_status_volume_widget->setText(text);
if (muted != m_status_volume_muted)
{
m_status_volume_muted = muted;
m_status_volume_widget->setIcon(QIcon::fromTheme(muted ? QStringLiteral("volume-mute-line") : QStringLiteral("volume-up-line")));
m_status_volume_toggle_mute_action->setIcon(QIcon::fromTheme(muted ? QStringLiteral("volume-up-line") : QStringLiteral("volume-mute-line")));
}
if (!muted && !m_status_volume_slider->isSliderDown())
{
QSignalBlocker blocker(m_status_volume_slider);
m_status_volume_slider->setValue(volume);
}
}
void MainWindow::setStatusGPUText(const QString& text)
{
m_status_gpu_widget->setText(text);
}
void MainWindow::setStatusFPSText(const QString& text)
{
m_status_fps_widget->setText(text);
}
void MainWindow::setStatusVPSText(const QString& text)
{
m_status_vps_widget->setText(text);
}
void MainWindow::setStatusSpeedText(const QString& text)
{
m_status_speed_widget->setText(text);
}
void MainWindow::updateWindowTitle()
@@ -2220,6 +2462,8 @@ void MainWindow::onVMStopped()
m_last_fps_status = empty_string;
m_status_renderer_widget->setText(empty_string);
m_status_resolution_widget->setText(empty_string);
m_status_volume_widget->setText(empty_string);
m_status_gpu_widget->setText(empty_string);
m_status_fps_widget->setText(empty_string);
m_status_vps_widget->setText(empty_string);
m_status_speed_widget->setText(empty_string);
@@ -3428,9 +3672,10 @@ void MainWindow::updateGameDependentActions()
m_ui.actionReloadPatches->setEnabled(s_vm_valid);
}
void MainWindow::updateGameGridActions(const bool show_game_grid)
void MainWindow::updateGameGridActions(const bool show_game_grid, const bool show_grid_cover_titles)
{
m_ui.actionGridViewShowTitles->setEnabled(show_game_grid);
m_ui.actionGridViewShowFullTitles->setEnabled(show_game_grid && show_grid_cover_titles);
m_ui.actionGridViewZoomIn->setEnabled(show_game_grid);
m_ui.actionGridViewZoomOut->setEnabled(show_game_grid);
m_ui.actionGridViewRefreshCovers->setEnabled(show_game_grid);

Some files were not shown because too many files have changed in this diff Show More