Dogway's grading shader (slang)

Thanks! I wasn’t debugging correctly - loading the single shader through GUI. And when loading the shader preset I forgot to disable crt-royale geometry mode (doesn’t work in vulkan yet).

Added a few fixes and uploaded; grade.glsl, grade.slang and ported white_point to slang too.

EDIT: Updated with new gamma function to fix the in/out gamma difference in the piece-wise function.

I noticed ntsc-adaptive is not in glsl, so I took a stab at porting it (pass1, pass2), it’s not possible right (runtime variables)?

1 Like

royale geometry should work with vulkan. What’s it doing on your end?

NTSC-adaptive should be port-able, I think, i just hadn’t gotten around to it, as I wasn’t sure if some lurking problem with the shader design was going to derail the whole endeavor. I’ll try to look it over soon.

2 Likes

It’s just rendering black for any mode (audio plays), and when changed to 0 it comes back.

I share the log but it looks like it doesn’t report any errors:

[INFO] [Vulkan]: Queue family 0 supports 16 sub-queues.
[INFO] [Vulkan]: Swapchain supports present mode: 2.
[INFO] [Vulkan]: Swapchain supports present mode: 3.
[INFO] [Vulkan]: Swapchain supports present mode: 1.
[INFO] [Vulkan]: Swapchain supports present mode: 0.
[INFO] [Vulkan]: Creating swapchain with present mode: 2
[INFO] [Vulkan]: Using swapchain size 2560 x 1440.
[INFO] [Vulkan]: Got 2 swapchain images.
[INFO] [Vulkan]: Using resolution 2560x1440
[INFO] [Vulkan]: Using BGRA8888 format.
[INFO] [Vulkan]: GPU supports linear images as textures, but not DEVICE_LOCAL. F
alling back to copy path.
[INFO] [Vulkan]: GPU supports linear images as textures, but not DEVICE_LOCAL. F
alling back to copy path.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\misc\grade.slang".
[INFO] [slang]: Using render target format R16G16B16A16_SFLOAT for pass output #
0.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\ntsc\shaders\ntsc-adaptive\ntsc-pass1.slang".
[INFO] [slang]: Using render target format R16G16B16A16_SFLOAT for pass output #
1.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\ntsc\shaders\ntsc-adaptive\ntsc-pass2.slang".
[INFO] [slang]: Using render target format R8G8B8A8_UNORM for pass output #2.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\crt\shaders\crt-royale\src\crt-royale-first-pass-linearize-crt-gamma-bob-fi
elds.slang".
[INFO] [slang]: Using render target format R8G8B8A8_SRGB for pass output #3.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\crt\shaders\crt-royale\src\crt-royale-scanlines-vertical-interlacing.slang"
.
[INFO] [slang]: Using render target format R8G8B8A8_SRGB for pass output #4.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\crt\shaders\crt-royale\src\crt-royale-bloom-approx.slang".
[INFO] [slang]: Using render target format R8G8B8A8_SRGB for pass output #5.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\blurs\blur9fast-vertical.slang".
[INFO] [slang]: Using render target format R8G8B8A8_SRGB for pass output #6.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\blurs\blur9fast-horizontal.slang".
[INFO] [slang]: Using render target format R8G8B8A8_SRGB for pass output #7.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\crt\shaders\crt-royale\src\crt-royale-mask-resize-vertical.slang".
[INFO] [slang]: Using render target format R8G8B8A8_UNORM for pass output #8.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\crt\shaders\crt-royale\src\crt-royale-mask-resize-horizontal.slang".
[INFO] [slang]: Using render target format R8G8B8A8_UNORM for pass output #9.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\crt\shaders\crt-royale\src\crt-royale-scanlines-horizontal-apply-mask.slang
".
[INFO] [slang]: Using render target format R8G8B8A8_SRGB for pass output #10.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\crt\shaders\crt-royale\src\crt-royale-brightpass.slang".
[INFO] [slang]: Using render target format R8G8B8A8_SRGB for pass output #11.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\crt\shaders\crt-royale\src\crt-royale-bloom-vertical.slang".
[INFO] [slang]: Using render target format R8G8B8A8_SRGB for pass output #12.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\crt\shaders\crt-royale\src\crt-royale-bloom-horizontal-reconstitute.slang".

[INFO] [slang]: Using render target format R8G8B8A8_SRGB for pass output #13.
[INFO] [slang]: Compiling shader "Y:\HyperSpin\Emulators\Super Nintendo Enter
tainment System\RetroArch 1.7.7 x64\shaders\presets\ParaLLEl N64\..\..\shaders_s
lang\crt\shaders\crt-royale\src\crt-royale-geometry-aa-last-pass.slang".
[INFO] [slang]: Using render target format R8G8B8A8_UNORM for pass output #14.
[INFO] [slang]: Building pass #0 (N/A)
[INFO] [Vulkan filter chain]: Creating framebuffer 1024 x 1024 (max 1 level(s)).

[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:      User (#0)
[INFO] [slang]:      User (#1)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OriginalSize (#0) (Offset: 80)
[INFO] [slang]:      SourceSize (#0) (Offset: 64)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #0 (PushOffset: 0)
[INFO] [slang]:     #1 (PushOffset: 4)
[INFO] [slang]:     #2 (PushOffset: 8)
[INFO] [slang]:     #3 (PushOffset: 12)
[INFO] [slang]:     #4 (PushOffset: 16)
[INFO] [slang]:     #5 (PushOffset: 20)
[INFO] [slang]:     #6 (PushOffset: 24)
[INFO] [slang]:     #7 (PushOffset: 28)
[INFO] [slang]:     #8 (PushOffset: 32)
[INFO] [slang]:     #9 (PushOffset: 36)
[INFO] [slang]:     #10 (PushOffset: 40)
[INFO] [slang]:     #11 (PushOffset: 44)
[INFO] [slang]:     #12 (PushOffset: 48)
[INFO] [slang]:     #13 (PushOffset: 56)
[INFO] [slang]:     #14 (PushOffset: 60)
[INFO] [slang]:     #15 (PushOffset: 64)
[INFO] [slang]:     #16 (PushOffset: 68)
[INFO] [slang]:     #17 (PushOffset: 72)
[INFO] [slang]:     #18 (PushOffset: 76)
[INFO] [slang]:     #19 (PushOffset: 80)
[INFO] [slang]:     #20 (PushOffset: 84)
[INFO] [slang]:     #21 (PushOffset: 88)
[INFO] [slang]:     #22 (PushOffset: 92)
[INFO] [slang]:     #23 (PushOffset: 96)
[INFO] [slang]:     #24 (PushOffset: 100)
[INFO] [slang]:     #25 (PushOffset: 104)
[INFO] [slang]:     #26 (PushOffset: 108)
[INFO] [slang]:     #27 (PushOffset: 112)
[INFO] [Vulkan]: Push Constant Block: 116 bytes.
[INFO] [slang]: Building pass #1 (N/A)
[INFO] [Vulkan filter chain]: Creating framebuffer 1536 x 1024 (max 1 level(s)).

[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: no, Fragment: no):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (Offset: 64)
[INFO] [slang]:      FrameCount (Offset: 112)
[INFO] [slang]:      OriginalSize (#0) (Offset: 80)
[INFO] [slang]:      SourceSize (#0) (Offset: 96)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #0 (Offset: 116)
[INFO] [slang]:     #1 (Offset: 120)
[INFO] [slang]: Building pass #2 (N/A)
[INFO] [Vulkan filter chain]: Creating framebuffer 768 x 1024 (max 1 level(s)).
[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: no, Fragment: no):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OriginalSize (#0) (Offset: 80)
[INFO] [slang]:      SourceSize (#0) (Offset: 96)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #0 (Offset: 112)
[INFO] [slang]: Building pass #3 (ORIG_LINEARIZED)
[INFO] [Vulkan filter chain]: Creating framebuffer 768 x 1024 (max 1 level(s)).
[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      FrameCount (PushOffset: 48)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #0 (Offset: 64)
[INFO] [slang]:     #43 (Offset: 244)
[INFO] [slang]:     #44 (Offset: 236)
[INFO] [slang]:     #45 (Offset: 240)
[INFO] [Vulkan]: Push Constant Block: 52 bytes.
[INFO] [slang]: Building pass #4 (VERTICAL_SCANLINES)
[INFO] [Vulkan filter chain]: Creating framebuffer 768 x 1440 (max 1 level(s)).
[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      FrameCount (PushOffset: 48)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #7 (Offset: 92)
[INFO] [slang]:     #8 (Offset: 96)
[INFO] [slang]:     #9 (Offset: 100)
[INFO] [slang]:     #10 (Offset: 104)
[INFO] [slang]:     #11 (Offset: 108)
[INFO] [slang]:     #12 (Offset: 112)
[INFO] [slang]:     #19 (Offset: 140)
[INFO] [slang]:     #20 (Offset: 144)
[INFO] [slang]:     #21 (Offset: 148)
[INFO] [slang]:     #43 (Offset: 244)
[INFO] [slang]:     #44 (Offset: 236)
[INFO] [slang]:     #45 (Offset: 240)
[INFO] [Vulkan]: Push Constant Block: 52 bytes.
[INFO] [slang]: Building pass #5 (BLOOM_APPROX)
[INFO] [Vulkan filter chain]: Creating framebuffer 320 x 240 (max 1 level(s)).
[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Original (#0)
[INFO] [slang]:      Source (#0)
[INFO] [slang]:      PassOutput (#3)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #8 (Offset: 96)
[INFO] [slang]:     #16 (Offset: 128)
[INFO] [slang]:     #17 (Offset: 132)
[INFO] [slang]:     #18 (Offset: 136)
[INFO] [slang]:     #19 (Offset: 140)
[INFO] [slang]:     #20 (Offset: 144)
[INFO] [slang]:     #21 (Offset: 148)
[INFO] [slang]:     #24 (Offset: 168)
[INFO] [slang]:     #25 (Offset: 164)
[INFO] [slang]:     #26 (Offset: 160)
[INFO] [slang]:     #36 (Offset: 208)
[INFO] [slang]:     #37 (Offset: 212)
[INFO] [slang]:     #43 (Offset: 244)
[INFO] [slang]:     #45 (Offset: 240)
[INFO] [Vulkan]: Push Constant Block: 80 bytes.
[INFO] [slang]: Building pass #6 (N/A)
[INFO] [Vulkan filter chain]: Creating framebuffer 320 x 240 (max 1 level(s)).
[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [Vulkan]: Push Constant Block: 52 bytes.
[INFO] [slang]: Building pass #7 (HALATION_BLUR)
[INFO] [Vulkan filter chain]: Creating framebuffer 320 x 240 (max 1 level(s)).
[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [Vulkan]: Push Constant Block: 52 bytes.
[INFO] [slang]: Building pass #8 (N/A)
[INFO] [Vulkan filter chain]: Creating framebuffer 64 x 90 (max 1 level(s)).
[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:      User (#2)
[INFO] [slang]:      User (#4)
[INFO] [slang]:      User (#6)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #22 (Offset: 152)
[INFO] [slang]:     #23 (Offset: 156)
[INFO] [slang]:     #24 (Offset: 168)
[INFO] [slang]:     #25 (Offset: 164)
[INFO] [slang]:     #26 (Offset: 160)
[INFO] [slang]:     #36 (Offset: 208)
[INFO] [slang]:     #37 (Offset: 212)
[INFO] [slang]:     #43 (Offset: 244)
[INFO] [Vulkan]: Push Constant Block: 52 bytes.
[INFO] [slang]: Building pass #9 (MASK_RESIZE)
[INFO] [Vulkan filter chain]: Creating framebuffer 120 x 90 (max 1 level(s)).
[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #23 (Offset: 156)
[INFO] [slang]:     #24 (Offset: 168)
[INFO] [slang]:     #25 (Offset: 164)
[INFO] [slang]:     #26 (Offset: 160)
[INFO] [slang]:     #43 (Offset: 244)
[INFO] [Vulkan]: Push Constant Block: 52 bytes.
[INFO] [slang]: Building pass #10 (MASKED_SCANLINES)
[INFO] [Vulkan filter chain]: Creating framebuffer 1920 x 1440 (max 1 level(s)).

[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:      PassOutput (#4)
[INFO] [slang]:      PassOutput (#5)
[INFO] [slang]:      PassOutput (#7)
[INFO] [slang]:      PassOutput (#9)
[INFO] [slang]:      User (#3)
[INFO] [slang]:      User (#5)
[INFO] [slang]:      User (#7)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:      PassOutputSize (#4) (PushOffset: 48)
[INFO] [slang]:      PassOutputSize (#5) (PushOffset: 64)
[INFO] [slang]:      PassOutputSize (#7) (PushOffset: 80)
[INFO] [slang]:      PassOutputSize (#9) (PushOffset: 96)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #3 (Offset: 76)
[INFO] [slang]:     #13 (Offset: 116)
[INFO] [slang]:     #14 (Offset: 120)
[INFO] [slang]:     #15 (Offset: 124)
[INFO] [slang]:     #16 (Offset: 128)
[INFO] [slang]:     #17 (Offset: 132)
[INFO] [slang]:     #18 (Offset: 136)
[INFO] [slang]:     #22 (Offset: 152)
[INFO] [slang]:     #23 (Offset: 156)
[INFO] [slang]:     #24 (Offset: 168)
[INFO] [slang]:     #25 (Offset: 164)
[INFO] [slang]:     #26 (Offset: 160)
[INFO] [slang]:     #43 (Offset: 244)
[INFO] [Vulkan]: Push Constant Block: 112 bytes.
[INFO] [slang]: Building pass #11 (BRIGHTPASS)
[INFO] [Vulkan filter chain]: Creating framebuffer 1920 x 1440 (max 1 level(s)).

[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      PassOutput (#5)
[INFO] [slang]:      PassOutput (#10)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:      PassOutputSize (#5) (PushOffset: 80)
[INFO] [slang]:      PassOutputSize (#10) (PushOffset: 64)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #2 (Offset: 72)
[INFO] [slang]:     #5 (Offset: 84)
[INFO] [slang]:     #6 (Offset: 88)
[INFO] [slang]:     #22 (Offset: 152)
[INFO] [slang]:     #23 (Offset: 156)
[INFO] [slang]:     #24 (Offset: 168)
[INFO] [slang]:     #25 (Offset: 164)
[INFO] [slang]:     #26 (Offset: 160)
[INFO] [slang]:     #43 (Offset: 244)
[INFO] [Vulkan]: Push Constant Block: 96 bytes.
[INFO] [slang]: Building pass #12 (N/A)
[INFO] [Vulkan filter chain]: Creating framebuffer 1920 x 1440 (max 1 level(s)).

[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #23 (Offset: 156)
[INFO] [slang]:     #24 (Offset: 168)
[INFO] [slang]:     #25 (Offset: 164)
[INFO] [slang]:     #26 (Offset: 160)
[INFO] [slang]:     #43 (Offset: 244)
[INFO] [Vulkan]: Push Constant Block: 96 bytes.
[INFO] [slang]: Building pass #13 (N/A)
[INFO] [Vulkan filter chain]: Creating framebuffer 1920 x 1440 (max 4294967295 l
evel(s)).
[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:      PassOutput (#7)
[INFO] [slang]:      PassOutput (#10)
[INFO] [slang]:      PassOutput (#11)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:      PassOutputSize (#7) (PushOffset: 64)
[INFO] [slang]:      PassOutputSize (#10) (PushOffset: 48)
[INFO] [slang]:      PassOutputSize (#11) (PushOffset: 80)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #2 (Offset: 72)
[INFO] [slang]:     #4 (Offset: 80)
[INFO] [slang]:     #22 (Offset: 152)
[INFO] [slang]:     #23 (Offset: 156)
[INFO] [slang]:     #24 (Offset: 168)
[INFO] [slang]:     #25 (Offset: 164)
[INFO] [slang]:     #26 (Offset: 160)
[INFO] [slang]:     #43 (Offset: 244)
[INFO] [Vulkan]: Push Constant Block: 96 bytes.
[INFO] [slang]: Building pass #14 (N/A)
[INFO] [Vulkan filter chain]: Creating framebuffer 1920 x 1440 (max 1 level(s)).

[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: yes):
[INFO] [slang]:   Push Constants (Vertex: yes, Fragment: yes):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:      OutputSize (PushOffset: 32)
[INFO] [slang]:      FrameCount (PushOffset: 48)
[INFO] [slang]:      SourceSize (#0) (PushOffset: 0)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [slang]:     #1 (Offset: 68)
[INFO] [slang]:     #29 (Offset: 180)
[INFO] [slang]:     #30 (Offset: 184)
[INFO] [slang]:     #31 (Offset: 188)
[INFO] [slang]:     #32 (Offset: 192)
[INFO] [slang]:     #33 (Offset: 196)
[INFO] [slang]:     #34 (Offset: 200)
[INFO] [slang]:     #35 (Offset: 204)
[INFO] [slang]:     #38 (Offset: 216)
[INFO] [slang]:     #39 (Offset: 220)
[INFO] [slang]:     #40 (Offset: 224)
[INFO] [slang]:     #41 (Offset: 228)
[INFO] [slang]:     #42 (Offset: 232)
[INFO] [slang]:     #43 (Offset: 244)
[INFO] [Vulkan]: Push Constant Block: 112 bytes.
[INFO] [slang]: Building pass #15 (N/A)
[INFO] [slang]: Reflection
[INFO] [slang]:   Textures:
[INFO] [slang]:      Source (#0)
[INFO] [slang]:
[INFO] [slang]:   Uniforms (Vertex: yes, Fragment: no):
[INFO] [slang]:   Push Constants (Vertex: no, Fragment: no):
[INFO] [slang]:      MVP (Offset: 0)
[INFO] [slang]:
[INFO] [slang]:   Parameters:
[INFO] [Vulkan filter chain]: Not using frame history.
[INFO] [Vulkan filter chain]: Not using framebuffer feedback.

any chance you’re using an old version? It should be fixed as of several months ago. Does it treat you any differently via GLCore?

1 Like

I updated the slang crt royale a month ago. With GL it’s fine. I share a preset I use just in case I missed something and whether it works on your end.

shaders = "15"
shader0 = "..\..\shaders_slang\misc\grade.slang"
filter_linear0 = "false"
wrap_mode0 = "clamp_to_border"
mipmap_input0 = "false"
alias0 = ""
float_framebuffer0 = "true"
srgb_framebuffer0 = "false"
scale_type_x0 = "source"
scale_x0 = "1.000000"
scale_type_y0 = "source"
scale_y0 = "1.000000"
shader1 = "..\..\shaders_slang\ntsc\shaders\ntsc-adaptive\ntsc-pass1.slang"
filter_linear1 = "false"
wrap_mode1 = "clamp_to_border"
frame_count_mod1 = "2"
mipmap_input1 = "false"
alias1 = ""
float_framebuffer1 = "true"
srgb_framebuffer1 = "false"
scale_type_x1 = "source"
scale_x1 = "5.000000"
scale_type_y1 = "source"
scale_y1 = "1.000000"
shader2 = "..\..\shaders_slang\ntsc\shaders\ntsc-adaptive\ntsc-pass2.slang"
filter_linear2 = "false"
wrap_mode2 = "clamp_to_border"
mipmap_input2 = "false"
alias2 = ""
float_framebuffer2 = "false"
srgb_framebuffer2 = "false"
scale_type_x2 = "source"
scale_x2 = "0.500000"
scale_type_y2 = "source"
scale_y2 = "1.000000"
shader3 = "..\..\shaders_slang\crt\shaders\crt-royale\src\crt-royale-first-pass-linearize-crt-gamma-bob-fields.slang"
filter_linear3 = "false"
wrap_mode3 = "clamp_to_border"
mipmap_input3 = "false"
alias3 = "ORIG_LINEARIZED"
float_framebuffer3 = "false"
srgb_framebuffer3 = "true"
scale_type_x3 = "source"
scale_x3 = "1.000000"
scale_type_y3 = "source"
scale_y3 = "1.000000"
shader4 = "..\..\shaders_slang\crt\shaders\crt-royale\src\crt-royale-scanlines-vertical-interlacing.slang"
filter_linear4 = "true"
wrap_mode4 = "clamp_to_border"
mipmap_input4 = "false"
alias4 = "VERTICAL_SCANLINES"
float_framebuffer4 = "false"
srgb_framebuffer4 = "true"
scale_type_x4 = "source"
scale_x4 = "1.000000"
scale_type_y4 = "viewport"
scale_y4 = "1.000000"
shader5 = "..\..\shaders_slang\crt\shaders\crt-royale\src\crt-royale-bloom-approx.slang"
filter_linear5 = "true"
wrap_mode5 = "clamp_to_border"
mipmap_input5 = "false"
alias5 = "BLOOM_APPROX"
float_framebuffer5 = "false"
srgb_framebuffer5 = "true"
scale_type_x5 = "absolute"
scale_x5 = "320"
scale_type_y5 = "absolute"
scale_y5 = "240"
shader6 = "..\..\shaders_slang\blurs\blur9fast-vertical.slang"
filter_linear6 = "true"
wrap_mode6 = "clamp_to_border"
mipmap_input6 = "false"
alias6 = ""
float_framebuffer6 = "false"
srgb_framebuffer6 = "true"
scale_type_x6 = "source"
scale_x6 = "1.000000"
scale_type_y6 = "source"
scale_y6 = "1.000000"
shader7 = "..\..\shaders_slang\blurs\blur9fast-horizontal.slang"
filter_linear7 = "true"
wrap_mode7 = "clamp_to_border"
mipmap_input7 = "false"
alias7 = "HALATION_BLUR"
float_framebuffer7 = "false"
srgb_framebuffer7 = "true"
scale_type_x7 = "source"
scale_x7 = "1.000000"
scale_type_y7 = "source"
scale_y7 = "1.000000"
shader8 = "..\..\shaders_slang\crt\shaders\crt-royale\src\crt-royale-mask-resize-vertical.slang"
filter_linear8 = "true"
wrap_mode8 = "clamp_to_border"
mipmap_input8 = "false"
alias8 = ""
float_framebuffer8 = "false"
srgb_framebuffer8 = "false"
scale_type_x8 = "absolute"
scale_x8 = "64"
scale_type_y8 = "viewport"
scale_y8 = "0.062500"
shader9 = "..\..\shaders_slang\crt\shaders\crt-royale\src\crt-royale-mask-resize-horizontal.slang"
filter_linear9 = "false"
wrap_mode9 = "clamp_to_border"
mipmap_input9 = "false"
alias9 = "MASK_RESIZE"
float_framebuffer9 = "false"
srgb_framebuffer9 = "false"
scale_type_x9 = "viewport"
scale_x9 = "0.062500"
scale_type_y9 = "source"
scale_y9 = "1.000000"
shader10 = "..\..\shaders_slang\crt\shaders\crt-royale\src\crt-royale-scanlines-horizontal-apply-mask.slang"
filter_linear10 = "true"
wrap_mode10 = "clamp_to_border"
mipmap_input10 = "false"
alias10 = "MASKED_SCANLINES"
float_framebuffer10 = "false"
srgb_framebuffer10 = "true"
scale_type_x10 = "viewport"
scale_x10 = "1.000000"
scale_type_y10 = "viewport"
scale_y10 = "1.000000"
shader11 = "..\..\shaders_slang\crt\shaders\crt-royale\src\crt-royale-brightpass.slang"
filter_linear11 = "true"
wrap_mode11 = "clamp_to_border"
mipmap_input11 = "false"
alias11 = "BRIGHTPASS"
float_framebuffer11 = "false"
srgb_framebuffer11 = "true"
scale_type_x11 = "viewport"
scale_x11 = "1.000000"
scale_type_y11 = "viewport"
scale_y11 = "1.000000"
shader12 = "..\..\shaders_slang\crt\shaders\crt-royale\src\crt-royale-bloom-vertical.slang"
filter_linear12 = "true"
wrap_mode12 = "clamp_to_border"
mipmap_input12 = "false"
alias12 = ""
float_framebuffer12 = "false"
srgb_framebuffer12 = "true"
scale_type_x12 = "source"
scale_x12 = "1.000000"
scale_type_y12 = "source"
scale_y12 = "1.000000"
shader13 = "..\..\shaders_slang\crt\shaders\crt-royale\src\crt-royale-bloom-horizontal-reconstitute.slang"
filter_linear13 = "true"
wrap_mode13 = "clamp_to_border"
mipmap_input13 = "false"
alias13 = ""
float_framebuffer13 = "false"
srgb_framebuffer13 = "true"
scale_type_x13 = "source"
scale_x13 = "1.000000"
scale_type_y13 = "source"
scale_y13 = "1.000000"
shader14 = "..\..\shaders_slang\crt\shaders\crt-royale\src\crt-royale-geometry-aa-last-pass.slang"
filter_linear14 = "true"
wrap_mode14 = "clamp_to_border"
mipmap_input14 = "true"
alias14 = ""
float_framebuffer14 = "false"
srgb_framebuffer14 = "false"
scale_type_x14 = "viewport"
scale_x14 = "1.000000"
scale_type_y14 = "viewport"
scale_y14 = "1.000000"
parameters = "quality;bw;linearize;gamma_type;gamma_in;vignette;str;power;LUT_Size1;LUT1_toggle;LUT_Size2;LUT2_toggle;temperature;luma_preserve;sat;lum;cntrst;black_level;blr;blg;blb;r;g;b;rg;rb;gr;gb;br;bg;crt_gamma;lcd_gamma;levels_contrast;halation_weight;diffusion_weight;bloom_underestimate_levels;bloom_excess;beam_min_sigma;beam_max_sigma;beam_spot_power;beam_min_shape;beam_max_shape;beam_shape_power;beam_horiz_filter;beam_horiz_sigma;beam_horiz_linear_rgb_weight;convergence_offset_x_r;convergence_offset_x_g;convergence_offset_x_b;convergence_offset_y_r;convergence_offset_y_g;convergence_offset_y_b;mask_type;mask_sample_mode_desired;mask_specify_num_triads;mask_triad_size_desired;mask_num_triads_desired;aa_subpixel_r_offset_x_runtime;aa_subpixel_r_offset_y_runtime;aa_cubic_c;aa_gauss_sigma;geom_mode_runtime;geom_radius;geom_view_dist;geom_tilt_angle_x;geom_tilt_angle_y;geom_aspect_ratio_x;geom_aspect_ratio_y;geom_overscan_x;geom_overscan_y;border_size;border_darkness;border_compress;interlace_detect_toggle;interlace_bff;interlace_1080i"
quality = "1.000000"
bw = "0.000000"
linearize = "0.000000"
gamma_in = "2.400000"
gamma_type = "1.000000"
vignette = "1.000000"
str = "40.000000"
power = "0.250000"
LUT_Size1 = "32.000000"
LUT1_toggle = "0.000000"
LUT_Size2 = "64.000000"
LUT2_toggle = "0.000000"
temperature = "9311.000000"
luma_preserve = "1.000000"
sat = "0.950000"
lum = "1.050000"
cntrst = "0.000000"
mid = "0.500000"
black_level = "0.040000"
blr = "0.000000"
blg = "0.000000"
blb = "0.000000"
r = "1.000000"
g = "1.000000"
b = "1.000000"
rg = "0.000000"
rb = "0.000000"
gr = "0.000000"
gb = "0.000000"
br = "0.000000"
bg = "0.050000"
crt_gamma = "2.200000"
lcd_gamma = "2.200000"
levels_contrast = "1.000000"
halation_weight = "0.000000"
diffusion_weight = "0.075000"
bloom_underestimate_levels = "0.800000"
bloom_excess = "0.000000"
beam_min_sigma = "0.020000"
beam_max_sigma = "0.300000"
beam_spot_power = "0.330000"
beam_min_shape = "2.000000"
beam_max_shape = "4.000000"
beam_shape_power = "0.250000"
beam_horiz_filter = "0.000000"
beam_horiz_sigma = "0.350000"
beam_horiz_linear_rgb_weight = "1.000000"
convergence_offset_x_r = "0.000000"
convergence_offset_x_g = "0.000000"
convergence_offset_x_b = "0.000000"
convergence_offset_y_r = "0.000000"
convergence_offset_y_g = "0.000000"
convergence_offset_y_b = "0.000000"
mask_type = "1.000000"
mask_sample_mode_desired = "0.000000"
mask_specify_num_triads = "0.000000"
mask_triad_size_desired = "3.000000"
mask_num_triads_desired = "480.000000"
aa_subpixel_r_offset_x_runtime = "-0.333333"
aa_subpixel_r_offset_y_runtime = "0.000000"
aa_cubic_c = "0.500000"
aa_gauss_sigma = "0.500000"
geom_mode_runtime = "1.000000"
geom_radius = "1.800000"
geom_view_dist = "2.000000"
geom_tilt_angle_x = "0.000000"
geom_tilt_angle_y = "0.000000"
geom_aspect_ratio_x = "432.000000"
geom_aspect_ratio_y = "329.000000"
geom_overscan_x = "1.000000"
geom_overscan_y = "1.000000"
border_size = "0.015000"
border_darkness = "2.000000"
border_compress = "2.500000"
interlace_detect_toggle = "0.000000"
interlace_bff = "0.000000"
interlace_1080i = "0.000000"
textures = "SamplerLUT1;SamplerLUT2;mask_grille_texture_small;mask_grille_texture_large;mask_slot_texture_small;mask_slot_texture_large;mask_shadow_texture_small;mask_shadow_texture_large"
SamplerLUT1 = "..\..\shaders_slang\reshade\shaders\LUT\Sony Trinitron Std D50 - Edit 1 - Gamma Unadjusted -32px.png"
SamplerLUT1_linear = "true"
SamplerLUT1_wrap_mode = "clamp_to_border"
SamplerLUT1_mipmap = "false"
SamplerLUT2 = "..\..\shaders_slang\reshade\shaders\LUT\SamsungH6640-2020-03-02XYZLUT+MTX.Rec709_2.4.png"
SamplerLUT2_linear = "true"
SamplerLUT2_wrap_mode = "clamp_to_border"
SamplerLUT2_mipmap = "false"
mask_grille_texture_small = "..\..\shaders_slang\crt\shaders\crt-royale\SamsungTileableLinearApertureGrille15Wide8And5d5SpacingResizeTo64.png"
mask_grille_texture_small_linear = "true"
mask_grille_texture_small_wrap_mode = "repeat"
mask_grille_texture_small_mipmap = "false"
mask_grille_texture_large = "..\..\shaders_slang\crt\shaders\crt-royale\SamsungTileableLinearApertureGrille15Wide8And5d5Spacing.png"
mask_grille_texture_large_linear = "true"
mask_grille_texture_large_wrap_mode = "repeat"
mask_grille_texture_large_mipmap = "true"
mask_slot_texture_small = "..\..\shaders_slang\crt\shaders\crt-royale\SamsungTileableLinearSlotMaskTall15Wide9And4d5Horizontal9d14VerticalSpacingResizeTo64.png"
mask_slot_texture_small_linear = "true"
mask_slot_texture_small_wrap_mode = "repeat"
mask_slot_texture_small_mipmap = "false"
mask_slot_texture_large = "..\..\shaders_slang\crt\shaders\crt-royale\SamsungTileableLinearSlotMaskTall15Wide9And4d5Horizontal9d14VerticalSpacing.png"
mask_slot_texture_large_linear = "true"
mask_slot_texture_large_wrap_mode = "repeat"
mask_slot_texture_large_mipmap = "true"
mask_shadow_texture_small = "..\..\shaders_slang\crt\shaders\crt-royale\SamsungTileableLinearShadowMaskEDPResizeTo64.png"
mask_shadow_texture_small_linear = "true"
mask_shadow_texture_small_wrap_mode = "repeat"
mask_shadow_texture_small_mipmap = "false"
mask_shadow_texture_large = "..\..\shaders_slang\crt\shaders\crt-royale\SamsungTileableLinearShadowMaskEDP.png"
mask_shadow_texture_large_linear = "true"
mask_shadow_texture_large_wrap_mode = "repeat"
mask_shadow_texture_large_mipmap = "true"
1 Like

By the way, I updated grade again to include Dullness/Vibrance and a few cosmetic changes. For now this is it for me on this shader.

As a side note I included a discriminatory POW vs sRGB gamma setting because I noticed that Medievil was using a pure power compensated gamma. I don’t know if this is by system or by game but I default it to sRGB because on most titles it improves the dynamic range in the low range.

Also I’m concerned on overshooting values, so I might consider in the future a soft roll-off to bring those back to range.

Here all updated shaders for reference: GitHub Dogway RetroArch Shaders

5 Likes

I know this a big ask, but could you possibly do a version of the grade shader without the vignette and LUTs?

I’m asking because I don’t personally know enough about color management and I’m afraid I’d end up messing things up (color-wise) by just removing them outright, without knowing how to compensate for the removal.

If you’re not interested in doing it, it’s cool, I just figured I’d ask.

Either way this is some quality work, I’m glad that you go it where you wanted!

1 Like

Can’t you toggle off those ones? I know that for the slang version you either point to an existing LUT file or it renders black, and that’s an annoyance. If that’s what you mean I can post a version here without that.

1 Like

Yeah, that’ll work for me, my main concern was removing the LUTs without breaking things in a color sense.

Thanks!

You can just change the LUTs in the preset to point to the existing passthru LUTs. You’ll have the (minor) performance impact, but the image won’t change.

1 Like

That’s why I was asking about removing them (not from his main branch, just a personal version), I mean if I don’t have to do anything complicated I could just remove them myself. (I probably could have worded everything better.)

So really the main questions are do I have to do anything special to remove them as compensation and how would I do the fragColor at the end with them removed for correct gamma?

If I know this I can probably just do it myself, lol.

Sorry, I entertained myself debugging a possible chroma banding issue, anyways here it is:

grade_(noLUT).slang

#version 450

layout(push_constant) uniform Push
{
    float gamma_out;
    float gamma_in;
    float gamma_type;
    float vignette;
    float str;
    float power;
    float temperature;
    float luma_preserve;
    float sat;
    float dulvibr;
    float lum;
    float size;
    float cntrst;
    float mid;
    float black_level;
    float blr;
    float blg;
    float blb;
    float r;
    float g;
    float b;
    float rg;
    float rb;
    float gr;
    float gb;
    float br;
    float bg;
} params;

/*
   Grade
   > Ubershader grouping some color related monolithic shaders like color-mangler, vignette, white_point,
   > and the addition of vibrance, black level, sigmoidal contrast and proper gamma transforms.

   Author: hunterk, Guest, Dr. Venom, Dogway
   License: Public domain
*/

#pragma parameter gamma_out "Display Gamma" 2.20 0.0 3.0 0.05
#pragma parameter gamma_in "CRT Gamma" 2.40 0.0 3.0 0.05
#pragma parameter gamma_type "CRT Gamma (POW = 0, sRGB = 1)" 1.0 0.0 1.0 1.0
#pragma parameter vignette "Vignette Toggle" 1.0 0.0 1.0 1.0
#pragma parameter str "Vignette Strength" 40.0 10.0 40.0 1.0
#pragma parameter power "Vignette Power" 0.20 0.0 0.5 0.01
#pragma parameter temperature "White Point" 9311.0 1031.0 12047.0 72.0
#pragma parameter luma_preserve "WP Preserve Luminance" 1.0 0.0 1.0 1.0
#pragma parameter sat "Saturation" 0.0 -1.0 2.0 0.02
#pragma parameter dulvibr "Dullness/Vibrance" 0.0 -1.0 1.0 0.05
#pragma parameter lum "Brightness" 1.0 0.0 2.0 0.01
#pragma parameter cntrst "Contrast" 0.0 -1.0 1.0 0.05
#pragma parameter mid "Contrast Pivot" 0.5 0.0 1.0 0.01
#pragma parameter black_level "Black Level" 0.0 -0.5 0.5 0.01
#pragma parameter blr "Black-Red Tint" 0.0 0.0 1.0 0.005
#pragma parameter blg "Black-Green Tint" 0.0 0.0 1.0 0.005
#pragma parameter blb "Black-Blue Tint" 0.0 0.0 1.0 0.005
#pragma parameter r "White-Red Tint" 1.0 0.0 2.0 0.01
#pragma parameter g "White-Green Tint" 1.0 0.0 2.0 0.01
#pragma parameter b "White-Blue Tint" 1.0 0.0 2.0 0.01
#pragma parameter rg "Red-Green Tint" 0.0 -1.0 1.0 0.005
#pragma parameter rb "Red-Blue Tint" 0.0 -1.0 1.0 0.005
#pragma parameter gr "Green-Red Tint" 0.0 -1.0 1.0 0.005
#pragma parameter gb "Green-Blue Tint" 0.0 -1.0 1.0 0.005
#pragma parameter br "Blue-Red Tint" 0.0 -1.0 1.0 0.005
#pragma parameter bg "Blue-Green Tint" 0.0 -1.0 1.0 0.005

layout(std140, set = 0, binding = 0) uniform UBO
{
    mat4 MVP;
    vec4 SourceSize;
    vec4 OriginalSize;
    vec4 OutputSize;
} global;

#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;

void main()
{
    gl_Position = global.MVP * Position;
    vTexCoord = TexCoord;
}

#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;


// White Point Mapping function
//
// From the first comment post (sRGB primaries and linear light compensated)
//      http://www.zombieprototypes.com/?p=210#comment-4695029660
// Based on the Neil Bartlett's blog update
//      http://www.zombieprototypes.com/?p=210
// Inspired itself by Tanner Helland's work
//      http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/

vec3 wp_adjust(vec3 color){

    float temp = params.temperature / 100.;
    float k = params.temperature / 10000.;
    float lk = log(k);

    vec3 wp = vec3(1.);

    // calculate RED
    wp.r = (temp <= 65.) ? 1. : 0.32068362618584273 + (0.19668730877673762 * pow(k - 0.21298613432655075, - 1.5139012907556737)) + (- 0.013883432789258415 * lk);

    // calculate GREEN
    float mg = 1.226916242502167 + (- 1.3109482654223614 * pow(k - 0.44267061967913873, 3.) * exp(- 5.089297600846147 * (k - 0.44267061967913873))) + (0.6453936305542096 * lk);
    float pg = 0.4860175851734596 + (0.1802139719519286 * pow(k - 0.14573069517701578, - 1.397716496795082)) + (- 0.00803698899233844 * lk);
    wp.g = (temp <= 65.5) ? ((temp <= 8.) ? 0. : mg) : pg;

    // calculate BLUE
    wp.b = (temp <= 19.) ? 0. : (temp >= 66.) ? 1. : 1.677499032830161 + (- 0.02313594016938082 * pow(k - 1.1367244820333684, 3.) * exp(- 4.221279555918655 * (k - 1.1367244820333684))) + (1.6550275798913296 * lk);

    // clamp
    wp.rgb = clamp(wp.rgb, vec3(0.), vec3(1.));

    // Linear color input
    return color * wp;
}

vec3 sRGB_to_XYZ(vec3 RGB){

    const mat3x3 m = mat3x3(
    0.4124564, 0.3575761, 0.1804375,
    0.2126729, 0.7151522, 0.0721750,
    0.0193339, 0.1191920, 0.9503041);
    return RGB * m;
}


vec3 XYZtoYxy(vec3 XYZ){

    float XYZrgb = XYZ.r+XYZ.g+XYZ.b;
    float Yxyg = (XYZrgb <= 0.0) ? 0.3805 : XYZ.r / XYZrgb;
    float Yxyb = (XYZrgb <= 0.0) ? 0.3769 : XYZ.g / XYZrgb;
    return vec3(XYZ.g, Yxyg, Yxyb);
}


vec3 XYZ_to_sRGB(vec3 XYZ){

    const mat3x3 m = mat3x3(
    3.2404542, -1.5371385, -0.4985314,
   -0.9692660,  1.8760108,  0.0415560,
    0.0556434, -0.2040259,  1.0572252);
    return XYZ * m;
}


vec3 YxytoXYZ(vec3 Yxy){

    float Xs = Yxy.r * (Yxy.g/Yxy.b);
    float Xsz = (Yxy.r <= 0.0) ? 0.0 : 1.0;
    vec3 XYZ = vec3(Xsz,Xsz,Xsz) * vec3(Xs, Yxy.r, (Xs/Yxy.g)-Xs-Yxy.r);
    return XYZ;
}

// This shouldn't be necessary but it seems some undefined values can
// creep in and each GPU vendor handles that differently. This keeps
// all values within a safe range
vec3 mixfix(vec3 a, vec3 b, float c)
{
    return (a.z < 1.0) ? mix(a, b, c) : a;
}


vec4 mixfix_v4(vec4 a, vec4 b, float c)
{
    return (a.z < 1.0) ? mix(a, b, c) : a;
}


float SatMask(float color_r, float color_g, float color_b)
{
    float max_rgb = max(color_r, max(color_g, color_b));
    float min_rgb = min(color_r, min(color_g, color_b));
    float msk = clamp((max_rgb - min_rgb) / (max_rgb + min_rgb), 0.0, 1.0);
    return msk;
}


float moncurve_r( float color, float gamma, float offs)
{
    // Reverse monitor curve
    color = clamp(color, 0.0, 1.0);
    float yb = pow( offs * gamma / ( ( gamma - 1.0) * ( 1.0 + offs)), gamma);
    float rs = pow( ( gamma - 1.0) / offs, gamma - 1.0) * pow( ( 1.0 + offs) / gamma, gamma);

    color = ( color > yb) ? ( 1.0 + offs) * pow( color, 1.0 / gamma) - offs : color * rs;
    return color;
}


vec3 moncurve_r_f3( vec3 color, float gamma, float offs)
{
    color.r = moncurve_r( color.r, gamma, offs);
    color.g = moncurve_r( color.g, gamma, offs);
    color.b = moncurve_r( color.b, gamma, offs);
    return color.rgb;
}


float moncurve_f( float color, float gamma, float offs)
{
    // Forward monitor curve
    color = clamp(color, 0.0, 1.0);
    float fs = (( gamma - 1.0) / offs) * pow( offs * gamma / ( ( gamma - 1.0) * ( 1.0 + offs)), gamma);
    float xb = offs / ( gamma - 1.0);

    color = ( color > xb) ? pow( ( color + offs) / ( 1.0 + offs), gamma) : color * fs;
    return color;
}

vec3 moncurve_f_f3( vec3 color, float gamma, float offs)
{
    color.r = moncurve_f( color.r, gamma, offs);
    color.g = moncurve_f( color.g, gamma, offs);
    color.b = moncurve_f( color.b, gamma, offs);
    return color.rgb;
}


//  Performs better in gamma encoded space
float contrast_sigmoid(float color, float cont, float pivot){

    cont = pow(cont + 1., 3.);

    float knee = 1. / (1. + exp(cont * pivot));
    float shldr = 1. / (1. + exp(cont * (pivot - 1.)));

    color = (1. / (1. + exp(cont * (pivot - color))) - knee) / (shldr - knee);

    return color;
}


//  Performs better in gamma encoded space
float contrast_sigmoid_inv(float color, float cont, float pivot){

    cont = pow(cont - 1., 3.);

    float knee = 1. / (1. + exp (cont * pivot));
    float shldr = 1. / (1. + exp (cont * (pivot - 1.)));

    color = pivot - log(1. / (color * (shldr - knee) + knee) - 1.) / cont;

    return color;
}



void main()
{

//  Pure power was crushing blacks (eg. DKC2). You can mimic pow(c, 2.4) by raising the gamma_in value to 2.55
    vec3 imgColor = texture(Source, vTexCoord.xy).rgb;
    imgColor = (params.gamma_type == 1.0) ? moncurve_f_f3(imgColor, params.gamma_in + 0.15, 0.055) : pow(imgColor, vec3(params.gamma_in));


//  Saturation agnostic sigmoidal contrast
    vec3 Yxy = XYZtoYxy(sRGB_to_XYZ(imgColor));
    float toLinear = moncurve_r(Yxy.r, 2.40, 0.055);
    float sigmoid = (params.cntrst > 0.0) ? contrast_sigmoid(toLinear, params.cntrst, params.mid) : contrast_sigmoid_inv(toLinear, params.cntrst, params.mid);
    vec3 contrast = vec3(moncurve_f(sigmoid, 2.40, 0.055), Yxy.g, Yxy.b);
    vec3 XYZsrgb = clamp(XYZ_to_sRGB(YxytoXYZ(contrast)), 0.0, 1.0);
    contrast = (params.cntrst == 0.0) ? imgColor : XYZsrgb;


//  Vignetting & Black Level
    vec2 vpos = vTexCoord*(global.OriginalSize.xy/global.SourceSize.xy);

    vpos *= 1.0 - vpos.xy;
    float vig = vpos.x*vpos.y * params.str;
    vig = min(pow(vig, params.power), 1.0);
    contrast *= (params.vignette == 1.0) ? vig : 1.0;

    contrast += (params.black_level / 20.0) * (1.0 - contrast);


//  RGB related transforms
    vec4 screen = vec4(max(contrast, 0.0), 1.0);
    float sat = params.sat + 1.0;

                   //  r               g           b  alpha ; alpha does nothing for our purposes
    mat4 color = mat4(params.r, params.rg,  params.rb,  0.0,  //red tint
                     params.gr,  params.g,  params.gb,  0.0,  //green tint
                     params.br, params.bg,   params.b,  0.0,  //blue tint
                    params.blr, params.blg, params.blb, 0.0); //black tint

    mat4 adjust = mat4((1.0 - sat) * 0.2126 + sat, (1.0 - sat) * 0.2126, (1.0 - sat) * 0.2126, 1.0,
                       (1.0 - sat) * 0.7152, (1.0 - sat) * 0.7152 + sat, (1.0 - sat) * 0.7152, 1.0,
                       (1.0 - sat) * 0.0722, (1.0 - sat) * 0.0722, (1.0 - sat) * 0.0722 + sat, 1.0,
                        0.0, 0.0, 0.0, 1.0);

    screen = clamp(screen * ((params.lum - 1.0) * 2.0 + 1.0), 0.0, 1.0);
    screen = color * screen;
    float sat_msk = (params.dulvibr > 0.0) ? clamp(1.0 - (SatMask(screen.r, screen.g, screen.b) * params.dulvibr), 0.0, 1.0) : clamp(1.0 - abs(SatMask(screen.r, screen.g, screen.b) - 1.0) * abs(params.dulvibr), 0.0, 1.0);
    screen = mixfix_v4(screen, adjust * screen, sat_msk);


//  Color Temperature
    vec3 adjusted = wp_adjust(screen.rgb);
    vec3 base_luma = XYZtoYxy(sRGB_to_XYZ(screen.rgb));
    vec3 adjusted_luma = XYZtoYxy(sRGB_to_XYZ(adjusted));
    adjusted = (params.luma_preserve == 1.0) ? adjusted_luma + (vec3(base_luma.r, 0.0, 0.0) - vec3(adjusted_luma.r, 0.0, 0.0)) : adjusted_luma;
    adjusted = clamp(XYZ_to_sRGB(YxytoXYZ(adjusted)), 0.0, 1.0);


    FragColor = vec4(moncurve_r_f3(adjusted, params.gamma_out + 0.20, 0.055), 1.0);
}
3 Likes

Your good man, you weren’t obligated to do anything anyway.

At least I don’t have to do it now, lol.

Really appreciate this!

2 Likes

Thanks again for the shader, looks great from my testing so far. Black level management is much better than in you’re earlier version (less drastic.)

The only thing I was having issues with was the dull/vibrance setting. I wasn’t really noticing any changes… (Maybe I need to take some screenshots for myself to compare it at -1 and 1?)

Looks good though, everything else was working great for me.

EDIT: Does the shader need to be ran with srgb_framebuffer set to true?

2 Likes

Thanks! Yes I refined some settings so there’s more granularity or goes from negative to positive as for me that’s easier to grasp. EDIT: srgb_framebuffer to false, we are doing gamma inside the shader.

Dullnes/Vibrance is actually a mask for Saturation. It won’t do anything if that’s 0. In my opinion this is a better solution because it also allows you to desaturate low saturated areas (akin bleach bypass if used with contrast), or saturate even more saturated areas. More control in less settings, think of it as a 2D plot where Y is Saturation and X is the saturation mask.

The issue with the chroma banding (and partly the overexposition) is due to the Brightness setting, despite working in 16-bit half float. I integrated a rolled-off gain for Brightness so it works in a gradual manner in the high range. The code is dirty as it is but it works fine. I also implemented a Hotspot fix to bring down some overexposed highlights and recover some shading in those areas, but I’m not happy at all with the code. You can toggle that off though.

Another big issue I was having was posterization or banding in the low range. I thought this was a quantization side-effect of doing several gamma transforms in chain, and although I optimized how the transforms are taking place (check the presets below) the real culprit was crt-royale beam-min-sigma, by default 0.02 it was darkening the image, set to 0.10 and clipping goes away (EDIT: As I found out, only an issue with > 240px input sizes). Still, I really would like if the ntsc passes would work in linear space (seemingly they are designed with gamma encoded inputs), because it could save us 2 transformations that translates to better performance and less quantization.

beam 0.02 beam 0.1

After an advice from hunterk I also modified the variable names. As usual updates in the repo. I’m also sharing the full presets with recommended default settings because it’s not easy stuff, for both slang and glsl and 240 and 320 inputs.

3 Likes

OMG, it was the atan() function in include\compat_macros.inc, I completely overlooked that since it’s not in the crt folder and my diff comparison software skipping minor changes. Finally after all these years I can get rid of glsl at last, thanks for making me look twice.

2 Likes

oh lol yep, I felt the same way when I figured out what was wrong… What a dumb problem to have caused us so much grief.

3 Likes

@Dogway

Man I feel dumb, I read your post about the dull/vibrance setting when I was half asleep, and was so confused. Re-read it today, looked at the graph and was fuuuuuu that’s what it does, lol. (I mean damn, you drew me a picture and everything, I’m not stupid I swear, rofl.)

You’re grade shader is great man, the white point lum preserve does alot for the image.

I need to update the copy you did without the LUTs to current, which I can most certainly do I’ll just cherry pick the update from the repo.

I did make two alterations to the shader though, I separated the saturation into separate RGB saturation(this may slightly be pointless as the dull/vibrance is a thing, but I like that grainual control), and added the X/Y Modifier’s from image-adjustment (mainly so I don’t need image-adjustment for it, lol.)

All in all this is my favorite video management shader.

2 Likes

@Dogway

Jesus, you’ve been busy over the last couple of days.

Decided I was going to start cherry picking that update for grade, opened up your repo and you went ham on updating grade. Also interesting update for the signal-bandwidth shader, will have to check it out.

2 Likes

oh well, many are cosmetics. I mainly implemented corner size since crt-royale doesn’t have that one. Ideally this fits better into image-adjustment (flip, mirror, zoom, translate, etc) but no way I’m going into that territory haha. The other thing was slang versions for lut_x2, gdapt stripes and signal-bandwidth.

BTW, I forgot to say that signal bandwidth for the ntsc passes is emulated through hardware resizing.

Those:

scale_type_x1 = "source"
scale_x1 = "4.000000"
scale_type_x2 = "source"
scale_x2 = "0.500000"

I’m not sure if this is a requirement for ntsc to work or an option, in which case I would replace that “hack” with signal-bandwidth. I guess after the ntsc passes.

1 Like