Skip to content

GS/DX12/VK: Shader based sprite round/clamp/align for upscaling. (WIP)#14187

Draft
TJnotJT wants to merge 5 commits intoPCSX2:masterfrom
TJnotJT:gs-accurate-uv-clamp
Draft

GS/DX12/VK: Shader based sprite round/clamp/align for upscaling. (WIP)#14187
TJnotJT wants to merge 5 commits intoPCSX2:masterfrom
TJnotJT:gs-accurate-uv-clamp

Conversation

@TJnotJT
Copy link
Copy Markdown
Contributor

@TJnotJT TJnotJT commented Mar 22, 2026

Status: Currently a WIP for testing so bug reports are appreciated.

Description of Changes

  • Add shader based sprite round/clamp/align for upscaling
  • Committed on top of GS: Accurate UV rounding for axis-aligned prims. #14078.
  • Currently disables other sprite upscaling fixes to make testing easier.
  • Not implemented yet for DX11/OGL, which might not work correctly in this build.

Rationale behind Changes

Details/Config

Implements the following sprite adjustments:

  • Alignment: aligns sprite to native coordinates.
  • Rounding: downscales texture coordinates to native resolution, does rounding, and then upscales again. May make some textures look blockier.
  • Clamping: clamp texture coordinates to maximum range used at native resolution. May clip some texture if they are also clipped at native.

Adds the following INI settings:

[EmuCore/GS]
AccurateUVRounding = 1
SpriteAlign = 2
  • AccurateUVRounding:
    • 0 (off)
    • 1 (on)
    • Default in this build is 1.
  • SpriteAlign:
    • 0 (off)
    • 1 (align)
    • 2 (align + clamp)
    • Default in this build is 2.

Limitations

  • AccurateUVRounding = 1 may cause some texture to lose resolution. Can sometimes be improved with AccurateUVRounding = 0 and keeping SpriteAlign = 2 to prevent lines.
  • SpriteAlign = 2 (clamp+align) can sometimes cause seams. Can sometimes be improved with SpriteAlign = 1 (align only).
  • Anything that is broken at native will likely be broken with this PR (e.g. fonts that appear clipped at native such Armored Core HUD).
  • May have seams in games that do copies with small sprites split over multiple draws (e.g. Tekken Tag Tournament and Mobile Suit Gundam).
  • May have misaligned UI element if the game uses a mix of right triangles and other geometry (e.g. Gran Turismo 4).
  • Todo: Does not yet handle right triangles that rotate textures 90 degrees (e.g. Everybody's Tennis UI).
  • Todo: Bilinear filtering with upscaling is currently broken. This causes bugs in games that use bilinear for antialiasing like Dragon Quest VIII and Jak and Daxter TPL.
  • Todo: Mainly tested on 2x upscaling, results may differ on higher upscales.

Suggested Testing Steps

Use DX12 or VK with 2x or higher upscaling. The following settings are enabled by default:

[EmuCore/GS]
AccurateUVRounding = 1 # on
SpriteAlign = 2 # align+clamp

The following may be better in some cases at reducing lines while keeping good UI quality:

[EmuCore/GS]
AccurateUVRounding = 0 # off
SpriteAlign = 2 # align+clamp

The followin may be better in some caes (e.g. some Tekken games) where there are seams in the frame:

[EmuCore/GS]
AccurateUVRounding = 1 # on
SpriteAlign = 1 # align

Did you use AI to help find, test, or implement this issue or feature?

To ask questions about GLSL/HLSL and other topics. Also see the answer here: #14078.

Comparisons (fixes)

bge.gs.xz (needs autoflush enabled)

Master 2x
02117_f00003_fr-1_03ec0_C_32

PR 2x
02117_f00003_fr-1_03ec0_C_32


Yu-Gi-Oh! The Duelists of the Roses_SLUS-20515_20250511091941.gs.xz (font lines)

Master 2x
00523_f00003_fr-1_008c0_C_16S

PR 2x (some font clipping as with native)
00523_f00003_fr-1_008c0_C_16S


Dynasty_Warriors_5_-_Xtreme_Legends_floor.gs.xz (lines in UI and floor)

Master 2x
S095821_f00002_fr1_00000_C_32_Dynasty_Warriors_5_-_Xtreme_Legends_floor gs xz_master

PR 2x
S095821_f00002_fr1_00000_C_32_Dynasty_Warriors_5_-_Xtreme_Legends_floor gs xz_accuv-clmp20-2


Street Fighter III - 3rd Strike_SLPM-65621_20220827100351.gs.xz (lines)

Master 2x
S041173_f00003_fr-1_01180_C_32_Street Fighter III - 3rd Strike_SLPM-65621_20220827100351 gs xz_master

PR 2x
S041173_f00003_fr-1_01180_C_32_Street Fighter III - 3rd Strike_SLPM-65621_20220827100351 gs xz_accuv-clmp20-2


Psychonauts_SLUS-21120_20240704234653.gs.xz (bloom on signs)

Master 2x
S064631_f00003_fr-1_00c00_C_24_Psychonauts_SLUS-21120_20240704234653 gs xz_master

PR 2x
S064631_f00003_fr-1_00c00_C_24_Psychonauts_SLUS-21120_20240704234653 gs xz_accuv-clmp20-2


Armored.core.2.Arena.text.gs.xz (font lines)

Master 2x
S020753_f00001_fr1_00000_C_32_Armored core 2 Arena text gs xz_master

PR 2x
S020753_f00001_fr1_00000_C_32_Armored core 2 Arena text gs xz_accuv-clmp20-2


Astro Boy_SLUS-20867_20260131162220.gs (UI lines)

Master 2x
05891_f00003_fr-1_00000_C_32

PR 2x
05891_f00003_fr-1_00000_C_32

Astro Boy_SLUS-20867_20260131162220.zip


Disney G-Force_SLUS-21891_20260131161732.gs (font lines)

Master 2x
00732_f00003_fr-1_00000_C_32

PR 2x
00732_f00003_fr-1_00000_C_32

Disney G-Force_SLUS-21891_20260131161732.zip


hack_Infection_3x.gs (font lines)

Master 2x
00571_f00003_fr-1_00e00_C_32

PR 2x (some blocky font like native)
00571_f00003_fr-1_00e00_C_32

hack_Infection_3x.zip

Comparisons (breaks)

Dragon Quest VIII - Journey of the Cursed King_SLES-53974_20240619012551.gs.xz (broken bilinear antialias, see face)

Master 2x
S097135_f00002_fr-1_00e00_C_24_Dragon Quest VIII - Journey of the Cursed King_SLES-53974_20240619012551 gs xz_master

PR 2x
S097135_f00002_fr-1_00e00_C_24_Dragon Quest VIII - Journey of the Cursed King_SLES-53974_20240619012551 gs xz_accuv-clmp20-2


Jak_and_Daxter_-_The_Precursor_Legacy_SCES-50361.gs.xz (broken bilinear antialias, fuzzy)

Master 2x
02383_f00001_fr0_02800_C_32

PR 2x
02383_f00001_fr0_02800_C_32


Pac-Man_World_2_SLUS-20224_20220816132032.gs.xz (blocky UI/balls; a bit better with rounding disabled)

Master 2x
00155_f00001_fr1_00000_C_32

PR 2x
00155_f00001_fr1_00000_C_32

PR 2x (AccurateUVRounding = 0, SpriteAlign = 2)
00155_f00001_fr1_00000_C_32


Armored_Core_2_SLUS-20014_20240407012352.gs.xz (fixes lines but lowers UI quality to native; a bit better with rounding disabled)

Master 2x
00836_f00001_fr1_008c0_C_32

PR 2x
00836_f00001_fr1_008c0_C_32

PR 2x (AccurateUVRounding = 0, SpriteAlign = 2)
00836_f00001_fr1_008c0_C_32

@Felipefpl
Copy link
Copy Markdown

Felipefpl commented Mar 22, 2026

Hi, Good to see Street Fighter 3 fixed. Thanks for that. 👍 Do you know if this fixes the black lines of HP/MP bars of Shining Force EXA? This is a bug that happens only when we upscale the game.
Shining Force EXA_SLUS-21567_20260219154120

@TJnotJT
Copy link
Copy Markdown
Contributor Author

TJnotJT commented Mar 22, 2026

Do you know if this fixes the black lines of HP/MP bars of Shining Force EXA? This is a bug that happens only when we upscale the game.

Yes, that screen is fixed at 2x (edit: there's a line next to "S" in the bottom-right that's also in SW so will need to be checked on a PS2):
00291_f00003_fr-1_00d00_C_24

However, it causes a line in another UI (also in master/PR SW) so it needs to be checked on a PS2:

Master 1x:
00098_f00001_fr-1_00d00_C_24

PR 1x (see above the "Piece"):
00098_f00001_fr-1_00d00_C_24

Edit: Looks like both lines occur on a PS2 also:

shining-force-ui-2-frame-1 shining-force-ui-1-frame-3

Shining Force EXA_SLUS-21567_20240617191607.gs.xz.zip
Shining Force EXA_SLUS-21567_20240617191638.gs.xz.zip

@Felipefpl
Copy link
Copy Markdown

@TJnotJT - NICE! Thanks for the info. :)

@TJnotJT TJnotJT force-pushed the gs-accurate-uv-clamp branch from 88f17f5 to c9e610f Compare March 22, 2026 17:40
@matitone71
Copy link
Copy Markdown

Fixes all the arcade Tekken games on Tekken 5:
(Screenshots all taken at 2x resolution with the default PR settings)

Master:
Tekken 5_SCES-53202_20260323092759

PR:
Tekken 5_SCES-53202_20260323092239

Master:
Tekken 5_SCES-53202_20260323092805

PR:
Tekken 5_SCES-53202_20260323092246

Master:
Tekken 5_SCES-53202_20260323092811

PR:
Tekken 5_SCES-53202_20260323092251

Tekken 4 has its UI fixed, but it has some weird small lines going across the screen now

Master:
Tekken 4_SLUS-20328_20260323092925

PR:
Tekken 4_SLUS-20328_20260323092545

@TJnotJT
Copy link
Copy Markdown
Contributor Author

TJnotJT commented Mar 23, 2026

Tekken 4 has its UI fixed, but it has some weird small lines going across the screen now

Thanks for catching that. I did some quick testing with a Tekken Tag dump, and setting SpriteAlign = 1 (align without clamp) seems to remove the seams. It may bring back the UI lines, though, so if you happen to have a dump of that specific scene, that would be helpful for further testing.

@matitone71
Copy link
Copy Markdown

SpriteAlign set to 1 does indeed remove the seams and the UI is still fixed, it's perfect now.

Tekken 4_SLUS-20328_20260324102954

@Shifroval
Copy link
Copy Markdown

Shifroval commented Mar 26, 2026

I can report that at least menu part of the bug was fixed, thank you, @TJnotJT !

But as I reported earlier in another pr, hub map, all icons and menu boxes are now all shifted to the right. Text looks a bit off too. Also all the circle borders around the icons are uneven, but they are not shifted. And my eyes are not decieving me here, if you fast scroll between two images in a viewer, you can see how the whole screen has a shift. I tried to reproduce the scene as close as I can in two different builds.

Master
hack Infection Part 1_SLUS-20267_20260326103704

PR
hack Infection Part 1_SLUS-20267_20260326103046

Actually AccurateUVRounding = 0 fixes the shift, but the fonts are off again and now icons shift is inverted. On the bright side, menu lines are still fixed
hack Infection Part 1_SLUS-20267_20260326110808

I've made two dumps of this frame (all with 3x scaling as before), first with default settings
.hack Infection Part 1_SLUS-20267_20260326103046.gs.zip

And this with rounding set to 0
.hack Infection Part 1_SLUS-20267_20260326110808.gs.zip

Hope you can get to the bottom of it.

Edit.
Sprite align 0 or 1 introduces lines on almost all sprites.

@TJnotJT
Copy link
Copy Markdown
Contributor Author

TJnotJT commented Mar 26, 2026

@Shifroval Thanks for testing and the feedback. The blocky text and alignment issues are a limitation of this PR, as it relies on native alignment/rounding as a guide. Here’s a frame captured on a PS2, showing similar issues:
dothack-ugly-ui-frame-3

We could try heuristics or additional settings to mitigate this, but that may be tricky and might fix some cases while breaking others. It’s something we could explore in the future.

@Mrlinkwii Mrlinkwii added this to the Release 2.8 milestone Mar 26, 2026
@Shifroval
Copy link
Copy Markdown

Shifroval commented Mar 27, 2026

Ok, I finally got my old ps2 up and running (SCPH-90008 with opl running games over ethernet), I've no capture card, but I fiddled with gsm settings to make image more or less acceptable to take a photo.
I can at last confirm that at least in my case the real ps2 indeed renders the map like this, with eneven edges and uncentered icons. I checked text boxes too and they are also rendered like with your fix applied. Sure, the game was developed on crts and for crts, so many artifacts we see now where masked by the shortcomings of the technology.
20260327_132919697

So I guess that concludes the case? The only thing that I still can't be certain about is the image shift, is it a byproduct of the fix, or the whole time pcsx2 was rendering the image wrong? I know you can run gs dumps on your ps2, @TJnotJT, could you please capture how they look for you? You see the shift too, right?
Here's the dump from master (the ones above are from this pr)
.hack Infection Part 1_SLUS-20267_20260327192115.gs.zip

Also I faintly remember there was a pr many years ago that fixed map rendering glitch, I believe it also 'fixed' how ps2 was rendering it, making it more geometrically accurate, but apparently less hardware accurate. For instance the screenshots of old lparchive playthrough have uneven edges, but centered icons, but that's from 2011
https://lparchive.org/hack-Series/Update%2002/

If the whole purpose of pcsx2 is to be as accurate to the real hardware as possible, then your fix actually nailed it down perfectly. But maybe the shift is still wrong.

@TJnotJT
Copy link
Copy Markdown
Contributor Author

TJnotJT commented Mar 28, 2026

The only thing that I still can't be certain about is the image shift, is it a byproduct of the fix, or the whole time pcsx2 was rendering the image wrong?

In many cases, the fix applied in #14078 results in a 1-pixel texture shift due to how the GS rounds UV coordinates.

Here are the frames for comparison, the map does appear to be shifted between PS2/PR and master.

PS2
dothack-ugly-ui-frame-3

PR
S009254_f00003_fr-1_00e00_C_32_dothack_text_bug gs xz_accuv

Master
S009254_f00003_fr-1_00e00_C_32_dothack_text_bug gs xz_master

@Shifroval
Copy link
Copy Markdown

Shifroval commented Mar 28, 2026

In many cases, the fix applied in #14078 results in a 1-pixel texture shift due to how the GS rounds UV coordinates.

Thank you for testing this, I can see that menu sprites are shifted, yes (and I think that's expected, as you say texture shift), but I'm more concerned about 3d geometry or viewport space (not sure how to call it here) shift. In all cases I never touched the camera and only paused the game at the exact same spot, you can see that 2 screens from PR have identical street and city geometry layout and position of the portal model on the screen (ignore npcs, they're always running around), but Master's viewport is slightly shifted to the left. I can reproduce these shots easily and in all cases can see it. On your frames I can only see sprite shift.
I know it's minor, but I'm concerned if it's something bad or unwanted. Open my first two screenshots in your favourite image viewer and scroll between them until you notice it. I don't know if it's something trivial or expected for you as a developer, but as a player and a tester I see the difference. I don't have a capture card, so can't do a direct PR to PS2 comparison, thus I can only judge by how pcsx2 renders the scene.

@TJnotJT
Copy link
Copy Markdown
Contributor Author

TJnotJT commented Mar 28, 2026

@Shifroval Yes, there is a viewport shift as well, the PR applies a native half-pixel offset to all geometry.

The idea is to align upscaled pixels with the native pixel grid so they map cleanly (e.g., at 2x, each native pixel corresponds to a 2×2 block; at 3x, 3×3, etc.). This makes it easier to snap sprites to native coordinates and do rounding, since the mapping between upscaled and native pixels is unambiguous.

There are definitely some downsides as noted in the OP, but I’m not entirely sure which of them are specifically due to the half-pixel offset versus the overall alignment/rounding approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants