From e755fbb0f282a014c52358bbec64205169974f4c Mon Sep 17 00:00:00 2001 From: MajorPainTheCactus Date: Sun, 6 Feb 2022 21:59:44 +0000 Subject: [PATCH] Refactored shader to support shadow and dot masks - added crt-shadow-mask-hdr.slang, crt-dot-mask-hdr.slang Added Bang & Olufsen TV preset (shadow mask) Added Toshiba Microfilter TV preset (dot mask) Renamed crt-sony-pvm-4k-hdr.slang to more general crt-aperture-grille-hdr.slang Moved header files into an include directory --- hdr/crt-bang-olufsen-4k-hdr.slangp | 36 ++ hdr/crt-sony-pvm-4k-hdr.slangp | 4 +- hdr/crt-toshiba-microfilter-4k-hdr.slangp | 36 ++ hdr/shaders/crt-aperture-grille-hdr.slang | 156 ++++++++ hdr/shaders/crt-shadow-mask-hdr.slang | 183 ++++++++++ hdr/shaders/crt-slot-mask-hdr.slang | 176 +++++++++ hdr/shaders/crt-sony-pvm-4k-hdr.slang | 382 -------------------- hdr/shaders/hdr10.slang | 2 +- hdr/shaders/include/developer_parameters.h | 26 ++ hdr/shaders/include/developer_properties.h | 28 ++ hdr/shaders/{ => include}/hdr10.h | 0 hdr/shaders/{ => include}/inverse_tonemap.h | 0 hdr/shaders/include/scanline_generation.h | 151 ++++++++ hdr/shaders/include/user_parameters.h | 23 ++ hdr/shaders/include/user_properties.h | 12 + hdr/shaders/inverse_tonemap.slang | 2 +- 16 files changed, 831 insertions(+), 386 deletions(-) create mode 100644 hdr/crt-bang-olufsen-4k-hdr.slangp create mode 100644 hdr/crt-toshiba-microfilter-4k-hdr.slangp create mode 100644 hdr/shaders/crt-aperture-grille-hdr.slang create mode 100644 hdr/shaders/crt-shadow-mask-hdr.slang create mode 100644 hdr/shaders/crt-slot-mask-hdr.slang delete mode 100644 hdr/shaders/crt-sony-pvm-4k-hdr.slang create mode 100644 hdr/shaders/include/developer_parameters.h create mode 100644 hdr/shaders/include/developer_properties.h rename hdr/shaders/{ => include}/hdr10.h (100%) rename hdr/shaders/{ => include}/inverse_tonemap.h (100%) create mode 100644 hdr/shaders/include/scanline_generation.h create mode 100644 hdr/shaders/include/user_parameters.h create mode 100644 hdr/shaders/include/user_properties.h diff --git a/hdr/crt-bang-olufsen-4k-hdr.slangp b/hdr/crt-bang-olufsen-4k-hdr.slangp new file mode 100644 index 0000000..ada6155 --- /dev/null +++ b/hdr/crt-bang-olufsen-4k-hdr.slangp @@ -0,0 +1,36 @@ +/* +A shader that specifically tries to emulate Bang & Olufsen with a slot mask screen but with full brightness. + +The novel thing about this shader is that it transforms the image output by the 'console/arcade/computer' into HDR space first i.e brightens it first and then applies +an slot mask afterwards which is kind of what a CRT would actually do - its kind of a kin to the electron beam (but nothing like it lol). + +My DisplayHDR 600 monitor does seem to get reasonably close to the brightness of my PVM - its not quite there but its close. I think DisplayHDR 1000 and above will be able to match. + +Currently defaults towards a XXXX CRT MAKE MODEL XXXX. + +To use: +Please Enable HDR in RetroArch 1.10+ + +NOTE: when this shader is envoked the Contrast, Peak Luminance and Paper White Luminance in the HDR menu do nothing instead set those values through the shader parameters + +For this shader set Paper White Luminance to above 700 and Peak Luminance to the peak luminance of your monitor. + +Also try to use a integer scaling - its just better - overscaling is fine/great. + +This shader doesn't do any geometry warping or bouncing of light around inside the screen - I think these effects just add unwanted noise, I know people disagree. Please feel free to make you own and add them + +Works only with the D3D11/D3D12/Vulkan drivers currently + +THIS SHADER DOES NOT SUPPORT WRGB OLED (Due to the sub pixel layout of WRGB - QD-OLED or LCD (and variants thereof screens are fine) +*/ + +shaders = "1" +feedback_pass = "0" + +shader0 = "shaders/crt-slot-mask-hdr.slang" +filter_linear0 = "false" +wrap_mode0 = "clamp_to_border" +mipmap_input0 = "false" +alias0 = "" +float_framebuffer0 = "false" +srgb_framebuffer0 = "false" diff --git a/hdr/crt-sony-pvm-4k-hdr.slangp b/hdr/crt-sony-pvm-4k-hdr.slangp index b0f34a9..83ea4ef 100644 --- a/hdr/crt-sony-pvm-4k-hdr.slangp +++ b/hdr/crt-sony-pvm-4k-hdr.slangp @@ -13,7 +13,7 @@ Please Enable HDR in RetroArch 1.10+ NOTE: when this shader is envoked the Contrast, Peak Luminance and Paper White Luminance in the HDR menu do nothing instead set those values through the shader parameters -For this shader set Peak Luminance AND Paper White Luminance to the peak luminance of your monitor. +For this shader set Paper White Luminance to above 700 and Peak Luminance to the peak luminance of your monitor. Also try to use a integer scaling - its just better - overscaling is fine/great. @@ -27,7 +27,7 @@ THIS SHADER DOES NOT SUPPORT WRGB OLED (Due to the sub pixel layout of WRGB - QD shaders = "1" feedback_pass = "0" -shader0 = "shaders/crt-sony-pvm-4k-hdr.slang" +shader0 = "shaders/crt-aperture-grille-hdr.slang" filter_linear0 = "false" wrap_mode0 = "clamp_to_border" mipmap_input0 = "false" diff --git a/hdr/crt-toshiba-microfilter-4k-hdr.slangp b/hdr/crt-toshiba-microfilter-4k-hdr.slangp new file mode 100644 index 0000000..8937e8c --- /dev/null +++ b/hdr/crt-toshiba-microfilter-4k-hdr.slangp @@ -0,0 +1,36 @@ +/* +A shader that specifically tries to emulate Toshiba MicroFilter monitor's with an shadow mask screen but with full brightness. + +The novel thing about this shader is that it transforms the image output by the 'console/arcade/computer' into HDR space first i.e brightens it first and then applies +an shadow mask afterwards which is kind of what a CRT would actually do - its kind of a kin to the electron beam (but nothing like it lol). + +My DisplayHDR 600 monitor does seem to get reasonably close to the brightness of my PVM - its not quite there but its close. I think DisplayHDR 1000 and above will be able to match. + +Currently defaults towards a XXXX CRT MAKE MODEL XXXX. + +To use: +Please Enable HDR in RetroArch 1.10+ + +NOTE: when this shader is envoked the Contrast, Peak Luminance and Paper White Luminance in the HDR menu do nothing instead set those values through the shader parameters + +For this shader set Paper White Luminance to above 700 and Peak Luminance to the peak luminance of your monitor. + +Also try to use a integer scaling - its just better - overscaling is fine/great. + +This shader doesn't do any geometry warping or bouncing of light around inside the screen - I think these effects just add unwanted noise, I know people disagree. Please feel free to make you own and add them + +Works only with the D3D11/D3D12/Vulkan drivers currently + +THIS SHADER DOES NOT SUPPORT WRGB OLED (Due to the sub pixel layout of WRGB - QD-OLED or LCD (and variants thereof screens are fine) +*/ + +shaders = "1" +feedback_pass = "0" + +shader0 = "shaders/crt-shadow-mask-hdr.slang" +filter_linear0 = "false" +wrap_mode0 = "clamp_to_border" +mipmap_input0 = "false" +alias0 = "" +float_framebuffer0 = "false" +srgb_framebuffer0 = "false" diff --git a/hdr/shaders/crt-aperture-grille-hdr.slang b/hdr/shaders/crt-aperture-grille-hdr.slang new file mode 100644 index 0000000..28e139f --- /dev/null +++ b/hdr/shaders/crt-aperture-grille-hdr.slang @@ -0,0 +1,156 @@ +#version 450 + +/* +A shader that tries to emulate a sony PVM type aperture grille screen but with full brightness. + +The novel thing about this shader is that it relies on the HDR shaders to brighten up the image so that when +we apply this shader which emulates the apperture grille the resulting screen isn't left too dark. + +I think you need at least a DisplayHDR 600 monitor but to get close to CRT levels of brightness I think DisplayHDR 1000. + +Please Enable HDR in RetroArch 1.10+ + +NOTE: when this shader is envoked the Contrast, Peak Luminance and Paper White Luminance in the HDR menu do nothing instead set those values through the shader parameters + +For this shader set Paper White Luminance to above 700 and Peak Luminance to the peak luminance of your monitor. + +Also try to use a integer scaling - its just better - overscaling is fine. + +This shader doesn't do any geometry warping or bouncing of light around inside the screen etc - I think these effects just add unwanted noise, I know people disagree. Please feel free to make you own and add them + +Dont use this shader directly - use the hdr\crt-make-model-hdr.slangp where make and model are the make and model of the CRT you want. + +THIS SHADER DOES NOT SUPPORT WRGB OLED (Due to the sub pixel layout of WRGB - RGB QD-OLED or LCD (and variants thereof screens are fine) +*/ + +#pragma format A2B10G10R10_UNORM_PACK32 + +#define WHITE_BALANCE_CONTROL 0 + +#include "include\hdr10.h" + +#if WHITE_BALANCE_CONTROL +//#include "include\white_balance.h" +#endif // WHITE_BALANCE_CONTROL + +layout(push_constant) uniform Push +{ +#include "include\user_properties.h" +#include "include\developer_properties.h" +} params; + +#include "include\user_parameters.h" +#include "include\developer_parameters.h" + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; +layout(location = 1) out float ScanlineSize; +layout(location = 2) out float InverseScanlineSize; +layout(location = 3) out vec3 Convergence; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord * vec2(1.00001); // To resolve rounding issues when sampling + + ScanlineSize = global.OutputSize.y / global.SourceSize.y; + InverseScanlineSize = 1.0f / ScanlineSize; + + Convergence = vec3(params.RedConvergence, params.GreenConvergence, params.BlueConvergence); +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 1) in float ScanlineSize; +layout(location = 2) in float InverseScanlineSize; +layout(location = 3) in vec3 Convergence; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +#define kRed vec3(1.0, 0.0, 0.0) +#define kGreen vec3(0.0, 1.0, 0.0) +#define kBlue vec3(0.0, 0.0, 1.0) +#define kMagenta vec3(1.0, 0.0, 1.0) +#define kYellow vec3(1.0, 1.0, 0.0) +#define kCyan vec3(0.0, 1.0, 1.0) +#define kBlack vec3(0.0, 0.0, 0.0) +#define kWhite vec3(1.0, 1.0, 1.0) + +#define kBGRAxis 2 +#define kTVLAxis 3 +#define kResolutionAxis 2 +#define kMaxMaskSize 7 + +#define kNotSupported { kBlack, kBlack, kBlack, kBlack, kBlack, kBlack, kBlack } + +#define kMG { kMagenta, kGreen, kBlack, kBlack, kBlack, kBlack, kBlack } +#define kGM { kGreen, kMagenta, kBlack, kBlack, kBlack, kBlack, kBlack } + +#define kBGR { kBlue, kGreen, kRed, kBlack, kBlack, kBlack, kBlack } +#define kRGB { kRed, kGreen, kBlue, kBlack, kBlack, kBlack, kBlack } + +#define kRGBX { kRed, kGreen, kBlue, kBlack, kBlack, kBlack, kBlack } +#define kBGRX { kBlue, kGreen, kRed, kBlack, kBlack, kBlack, kBlack } + +#define kRYCBX { kRed, kYellow, kCyan, kBlue, kBlack, kBlack, kBlack } +#define kBCYRX { kBlue, kCyan, kYellow, kRed, kBlack, kBlack, kBlack } + +#define kRRGGBBX { kRed, kRed, kGreen, kGreen, kBlue, kBlue, kBlack } +#define kBBGGRRX { kBlue, kBlue, kGreen, kGreen, kRed, kRed, kBlack } + +const uint kPhosphorMaskSize[kResolutionAxis][kTVLAxis] = { { 4, 3, 2 }, { 7, 5, 4 } }; //4K: 600 TVL, 800 TVL, 1000 TVL 8K: 600 TVL, 800 TVL, 1000 TVL + +const vec3 kPhosphorMasks[kResolutionAxis][kTVLAxis][kBGRAxis][kMaxMaskSize] = { + { // 4K + { kRGBX, kBGRX }, // 600 TVL + { kBGR, kRGB }, // 800 TVL + { kMG, kGM } // 1000 TVL + }, + { // 8K + { kRRGGBBX, kBBGGRRX }, // 600 TVL + { kRYCBX, kRYCBX }, // 800 TVL + { kRGBX, kBGRX } // 1000 TVL + } +}; + +float ModInteger(float a, float b) +{ + float m = a - floor((a + 0.5) / b) * b; + return floor(m + 0.5); +} + +#include "include\scanline_generation.h" + +void main() +{ + const vec2 current_position = vTexCoord * global.OutputSize.xy; + + vec3 scanline_colour = GenerateScanline(current_position); + + { + uint lcd_subpixel_layout = uint(params.LCDSubpixel); + uint crt_resolution = uint(params.CRTResolution); + uint lcd_resolution = uint(params.LCDResolution); + + uint mask = uint(ModInteger(floor(current_position.x), kPhosphorMaskSize[lcd_resolution][crt_resolution])); + + scanline_colour *= kPhosphorMasks[lcd_resolution][crt_resolution][lcd_subpixel_layout][mask]; + } + + // HACK: To get maximum brightness we just set paper white luminance to max luminance + const vec3 hdr10 = Hdr10(scanline_colour, params.PaperWhiteNits, params.ExpandGamut); + + //FragColor = vec4(scanline_colour, 1.0); + FragColor = vec4(hdr10, 1.0); +} diff --git a/hdr/shaders/crt-shadow-mask-hdr.slang b/hdr/shaders/crt-shadow-mask-hdr.slang new file mode 100644 index 0000000..ffefe1c --- /dev/null +++ b/hdr/shaders/crt-shadow-mask-hdr.slang @@ -0,0 +1,183 @@ +#version 450 + +/* +A shader that tries to emulate a shadow mask screens but with full brightness. + +The novel thing about this shader is that it relies on the HDR shaders to brighten up the image so that when +we apply this shader which emulates the apperture grille the resulting screen isn't left too dark. + +I think you need at least a DisplayHDR 600 monitor but to get close to CRT levels of brightness I think DisplayHDR 1000. + +Please Enable HDR in RetroArch 1.10+ + +NOTE: when this shader is envoked the Contrast, Peak Luminance and Paper White Luminance in the HDR menu do nothing instead set those values through the shader parameters + +For this shader set Paper White Luminance to above 700 and Peak Luminance to the peak luminance of your monitor. + +Also try to use a integer scaling - its just better - overscaling is fine. + +This shader doesn't do any geometry warping or bouncing of light around inside the screen etc - I think these effects just add unwanted noise, I know people disagree. Please feel free to make you own and add them + +Dont use this shader directly - use the hdr\crt-make-model-hdr.slangp where make and model are the make and model of the CRT you want. + +THIS SHADER DOES NOT SUPPORT WRGB OLED (Due to the sub pixel layout of WRGB - RGB QD-OLED or LCD (and variants thereof screens are fine) +*/ + +#pragma format A2B10G10R10_UNORM_PACK32 + +#define WHITE_BALANCE_CONTROL 0 + +#include "include\hdr10.h" + +#if WHITE_BALANCE_CONTROL +//#include "include\white_balance.h" +#endif // WHITE_BALANCE_CONTROL + +layout(push_constant) uniform Push +{ +#include "include\user_properties.h" +#include "include\developer_properties.h" +} params; + +#include "include\user_parameters.h" +#include "include\developer_parameters.h" + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; +layout(location = 1) out float ScanlineSize; +layout(location = 2) out float InverseScanlineSize; +layout(location = 3) out vec3 Convergence; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord * vec2(1.00001); // To resolve rounding issues when sampling + + ScanlineSize = global.OutputSize.y / global.SourceSize.y; + InverseScanlineSize = 1.0f / ScanlineSize; + + Convergence = vec3(params.RedConvergence, params.GreenConvergence, params.BlueConvergence); +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 1) in float ScanlineSize; +layout(location = 2) in float InverseScanlineSize; +layout(location = 3) in vec3 Convergence; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +#define kRed vec3(1.0, 0.0, 0.0) +#define kGreen vec3(0.0, 1.0, 0.0) +#define kBlue vec3(0.0, 0.0, 1.0) +#define kMagenta vec3(1.0, 0.0, 1.0) +#define kYellow vec3(1.0, 1.0, 0.0) +#define kCyan vec3(0.0, 1.0, 1.0) +#define kBlack vec3(0.0, 0.0, 0.0) +#define kWhite vec3(1.0, 1.0, 1.0) + +#define kBGRAxis 2 +#define kTVLAxis 3 +#define kResolutionAxis 2 +#define kMaxMaskSize 8 +#define kMaxShadowSize 2 + +#define kXXXX { kBlack, kBlack, kBlack, kBlack, kBlack, kBlack, kBlack, kBlack } + +#define kMG { kMagenta, kGreen, kBlack, kBlack, kBlack, kBlack, kBlack, kBlack } +#define kGM { kGreen, kMagenta, kBlack, kBlack, kBlack, kBlack, kBlack, kBlack } + +#define kBGR { kBlue, kGreen, kRed, kBlack, kBlack, kBlack, kBlack, kBlack } +#define kRGB { kRed, kGreen, kBlue, kBlack, kBlack, kBlack, kBlack, kBlack } + +#define kRGBX { kRed, kGreen, kBlue, kBlack, kBlack, kBlack, kBlack, kBlack } +#define kBGRX { kBlue, kGreen, kRed, kBlack, kBlack, kBlack, kBlack, kBlack } + +#define kXRGB { kBlack, kRed, kGreen, kBlue, kBlack, kBlack, kBlack, kBlack } +#define kXBGR { kBlack, kBlue, kGreen, kRed, kBlack, kBlack, kBlack, kBlack } + +#define kRYCBX { kRed, kYellow, kCyan, kBlue, kBlack, kBlack, kBlack, kBlack } +#define kBCYRX { kBlue, kCyan, kYellow, kRed, kBlack, kBlack, kBlack, kBlack } + +#define kXRYCB { kBlack, kRed, kYellow, kCyan, kBlue, kBlack, kBlack, kBlack } +#define kXBCYR { kBlack, kBlue, kCyan, kYellow, kRed, kBlack, kBlack, kBlack } + +#define kRRGGBBX { kRed, kRed, kGreen, kGreen, kBlue, kBlue, kBlack, kBlack } +#define kBBGGRRX { kBlue, kBlue, kGreen, kGreen, kRed, kRed, kBlack, kBlack } + +#define kXRRGGBB { kBlack, kRed, kRed, kGreen, kGreen, kBlue, kBlue, kBlack } +#define kXBBGGRR { kBlack, kBlue, kBlue, kGreen, kGreen, kRed, kRed, kBlack } + +#define kMG_GM { kMG, kGM } +#define kGM_MG { kGM, kMG } + +#define kBGR_BGR { kBGR, kRGB } +#define kRGB_RGB { kRGB, kBGR } + +#define kRGBX_BGRX { kRGBX, kXRGB } +#define kBGRX_RGBX { kBGRX, kXBGR } + +#define kRYCBX_BCYRX { kRYCBX, kXRYCB } +#define kBCYRX_RYCBX { kBCYRX, kXBCYR } + +#define kRRGGBBX_BBGGRRX { kRRGGBBX, kXRRGGBB } +#define kBBGGRRX_RRGGBBX { kBBGGRRX, kXBBGGRR } + +const uint kPhosphorMaskSize[kResolutionAxis][kTVLAxis] = { { 4, 3, 2 }, { 7, 5, 4 } }; //4K: 600 TVL, 800 TVL, 1000 TVL 8K: 600 TVL, 800 TVL, 1000 TVL + +const vec3 kPhosphorMasks[kResolutionAxis][kTVLAxis][kBGRAxis][kMaxShadowSize][kMaxMaskSize] = { + { // 4K + { kRGBX_BGRX, kBGRX_RGBX }, // 600 TVL + { kBGR_BGR, kRGB_RGB }, // 800 TVL + { kMG_GM, kGM_MG } // 1000 TVL + }, + { // 8K + { kRRGGBBX_BBGGRRX, kBBGGRRX_RRGGBBX }, // 600 TVL + { kRYCBX_BCYRX, kBCYRX_RYCBX }, // 800 TVL + { kRGBX_BGRX, kBGRX_RGBX } // 1000 TVL + } +}; + +float ModInteger(float a, float b) +{ + float m = a - floor((a + 0.5) / b) * b; + return floor(m + 0.5); +} + +#include "include\scanline_generation.h" + +void main() +{ + const vec2 current_position = vTexCoord * global.OutputSize.xy; + + vec3 scanline_colour = GenerateScanline(current_position); + + { + uint lcd_subpixel_layout = uint(params.LCDSubpixel); + uint crt_resolution = uint(params.CRTResolution); + uint lcd_resolution = uint(params.LCDResolution); + + uint shadow_y = uint(ModInteger(floor(current_position.y), kMaxShadowSize)); + + uint mask = uint(ModInteger(floor(current_position.x), kPhosphorMaskSize[lcd_resolution][crt_resolution])); + + scanline_colour *= kPhosphorMasks[lcd_resolution][crt_resolution][lcd_subpixel_layout][shadow_y][mask]; + } + + // HACK: To get maximum brightness we just set paper white luminance to max luminance + const vec3 hdr10 = Hdr10(scanline_colour, params.PaperWhiteNits, params.ExpandGamut); + + //FragColor = vec4(scanline_colour, 1.0); + FragColor = vec4(hdr10, 1.0); +} diff --git a/hdr/shaders/crt-slot-mask-hdr.slang b/hdr/shaders/crt-slot-mask-hdr.slang new file mode 100644 index 0000000..76fd39c --- /dev/null +++ b/hdr/shaders/crt-slot-mask-hdr.slang @@ -0,0 +1,176 @@ +#version 450 + +/* +A shader that tries to emulate a slot mask screens but with full brightness. + +The novel thing about this shader is that it relies on the HDR shaders to brighten up the image so that when +we apply this shader which emulates the slot mask the resulting screen isn't left too dark. + +I think you need at least a DisplayHDR 600 monitor but to get close to CRT levels of brightness I think DisplayHDR 1000. + +Please Enable HDR in RetroArch 1.10+ + +NOTE: when this shader is envoked the Contrast, Peak Luminance and Paper White Luminance in the HDR menu do nothing instead set those values through the shader parameters + +For this shader set Paper White Luminance to above 700 and Peak Luminance to the peak luminance of your monitor. + +Also try to use a integer scaling - its just better - overscaling is fine. + +This shader doesn't do any geometry warping or bouncing of light around inside the screen etc - I think these effects just add unwanted noise, I know people disagree. Please feel free to make you own and add them + +Dont use this shader directly - use the hdr\crt-make-model-hdr.slangp where make and model are the make and model of the CRT you want. + +THIS SHADER DOES NOT SUPPORT WRGB OLED (Due to the sub pixel layout of WRGB - RGB QD-OLED or LCD (and variants thereof screens are fine) +*/ + +#pragma format A2B10G10R10_UNORM_PACK32 + +#define WHITE_BALANCE_CONTROL 0 + +#include "include\hdr10.h" + +#if WHITE_BALANCE_CONTROL +//#include "include\white_balance.h" +#endif // WHITE_BALANCE_CONTROL + +layout(push_constant) uniform Push +{ +#include "include\user_properties.h" +#include "include\developer_properties.h" +} params; + +#include "include\user_parameters.h" +#include "include\developer_parameters.h" + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; +layout(location = 1) out float ScanlineSize; +layout(location = 2) out float InverseScanlineSize; +layout(location = 3) out vec3 Convergence; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord * vec2(1.00001); // To resolve rounding issues when sampling + + ScanlineSize = global.OutputSize.y / global.SourceSize.y; + InverseScanlineSize = 1.0f / ScanlineSize; + + Convergence = vec3(params.RedConvergence, params.GreenConvergence, params.BlueConvergence); +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 1) in float ScanlineSize; +layout(location = 2) in float InverseScanlineSize; +layout(location = 3) in vec3 Convergence; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +#define kRed vec3(1.0, 0.0, 0.0) +#define kGreen vec3(0.0, 1.0, 0.0) +#define kBlue vec3(0.0, 0.0, 1.0) +#define kMagenta vec3(1.0, 0.0, 1.0) +#define kYellow vec3(1.0, 1.0, 0.0) +#define kCyan vec3(0.0, 1.0, 1.0) +#define kBlack vec3(0.0, 0.0, 0.0) +#define kWhite vec3(1.0, 1.0, 1.0) + +#define kBGRAxis 2 +#define kTVLAxis 3 +#define kResolutionAxis 2 +#define kMaxMaskSize 8 +#define kMaxSlotSizeX 2 +#define kMaxSlotSizeY 4 + +#define kXXXX { kBlack, kBlack, kBlack, kBlack, kBlack, kBlack, kBlack, kBlack } + +#define kMG { kMagenta, kGreen, kBlack, kBlack, kBlack, kBlack, kBlack, kBlack } +#define kGM { kGreen, kMagenta, kBlack, kBlack, kBlack, kBlack, kBlack, kBlack } + +#define kBGR { kBlue, kGreen, kRed, kBlack, kBlack, kBlack, kBlack, kBlack } +#define kRGB { kRed, kGreen, kBlue, kBlack, kBlack, kBlack, kBlack, kBlack } + +#define kRGBX { kRed, kGreen, kBlue, kBlack, kBlack, kBlack, kBlack, kBlack } +#define kBGRX { kBlue, kGreen, kRed, kBlack, kBlack, kBlack, kBlack, kBlack } + +#define kRYCBX { kRed, kYellow, kCyan, kBlue, kBlack, kBlack, kBlack, kBlack } +#define kBCYRX { kBlue, kCyan, kYellow, kRed, kBlack, kBlack, kBlack, kBlack } + +#define kRRGGBBX { kRed, kRed, kGreen, kGreen, kBlue, kBlue, kBlack, kBlack } +#define kBBGGRRX { kBlue, kBlue, kGreen, kGreen, kRed, kRed, kBlack, kBlack } + +#define kMGMG_MGXX_MGMG_XXMG { { kMG, kMG }, { kMG, kXXXX }, { kMG, kMG }, { kXXXX, kMG } } +#define kGMGM_GMXX_GMGM_XXGM { { kGM, kGM }, { kGM, kXXXX }, { kGM, kGM }, { kXXXX, kGM } } + +#define kBGRBGR_BGRXXX_BGRBGR_XXXBGR { { kBGR, kBGR }, { kBGR, kXXXX }, { kBGR, kBGR }, { kXXXX, kBGR } } +#define kRGBRGB_RGBXXX_RGBRGB_XXXRGB { { kRGB, kRGB }, { kRGB, kXXXX }, { kRGB, kRGB }, { kXXXX, kRGB } } + +#define kRGBXRGBX_RGBXXXXX_RGBXRGBX_XXXXRGBX { { kRGBX, kRGBX }, { kRGBX, kXXXX }, { kRGBX, kRGBX }, { kXXXX, kRGBX } } +#define kBGRXBGRX_BGRXXXXX_BGRXBGRX_XXXXBGRX { { kBGRX, kBGRX }, { kBGRX, kXXXX }, { kBGRX, kBGRX }, { kXXXX, kBGRX } } + +#define kRYCBXRYCBX_RYCBXXXXX_RYCBXRYCBX_XXXXRYCBX { { kRYCBX, kRYCBX }, { kRYCBX, kXXXX }, { kRYCBX, kRYCBX }, { kXXXX, kRYCBX } } +#define kBCYRXBCYRX_BCYRXXXXX_BCYRXBCYRX_XXXXBCYRX { { kBCYRX, kBCYRX }, { kBCYRX, kXXXX }, { kBCYRX, kBCYRX }, { kXXXX, kBCYRX } } + +#define kRRGGBBXRRGGBBX_RRGGBBXXXXX_RRGGBBXRRGGBBX_XXXXRRGGBBX { { kRRGGBBX, kRRGGBBX }, { kRRGGBBX, kXXXX }, { kRRGGBBX, kRRGGBBX }, { kXXXX, kRRGGBBX } } +#define kBBGGRRXBBGGRRX_BBGGRRXXXXX_BBGGRRXBBGGRRX_XXXXBBGGRRX { { kBBGGRRX, kBBGGRRX }, { kBBGGRRX, kXXXX }, { kBBGGRRX, kBBGGRRX }, { kXXXX, kBBGGRRX } } + +const uint kPhosphorMaskSize[kResolutionAxis][kTVLAxis] = { { 4, 3, 2 }, { 7, 5, 4 } }; //4K: 600 TVL, 800 TVL, 1000 TVL 8K: 600 TVL, 800 TVL, 1000 TVL + +const vec3 kPhosphorMasks[kResolutionAxis][kTVLAxis][kBGRAxis][kMaxSlotSizeY][kMaxSlotSizeX][kMaxMaskSize] = { + { // 4K + { kRGBXRGBX_RGBXXXXX_RGBXRGBX_XXXXRGBX, kBGRXBGRX_BGRXXXXX_BGRXBGRX_XXXXBGRX }, // 600 TVL + { kBGRBGR_BGRXXX_BGRBGR_XXXBGR, kRGBRGB_RGBXXX_RGBRGB_XXXRGB }, // 800 TVL + { kMGMG_MGXX_MGMG_XXMG, kGMGM_GMXX_GMGM_XXGM } // 1000 TVL + }, + { // 8K + { kRRGGBBXRRGGBBX_RRGGBBXXXXX_RRGGBBXRRGGBBX_XXXXRRGGBBX, kBBGGRRXBBGGRRX_BBGGRRXXXXX_BBGGRRXBBGGRRX_XXXXBBGGRRX }, // 600 TVL + { kRYCBXRYCBX_RYCBXXXXX_RYCBXRYCBX_XXXXRYCBX, kBCYRXBCYRX_BCYRXXXXX_BCYRXBCYRX_XXXXBCYRX }, // 800 TVL + { kRGBXRGBX_RGBXXXXX_RGBXRGBX_XXXXRGBX, kBGRXBGRX_BGRXXXXX_BGRXBGRX_XXXXBGRX } // 1000 TVL + } +}; + +float ModInteger(float a, float b) +{ + float m = a - floor((a + 0.5) / b) * b; + return floor(m + 0.5); +} + +#include "include\scanline_generation.h" + +void main() +{ + const vec2 current_position = vTexCoord * global.OutputSize.xy; + + vec3 scanline_colour = GenerateScanline(current_position); + + { + uint lcd_subpixel_layout = uint(params.LCDSubpixel); + uint crt_resolution = uint(params.CRTResolution); + uint lcd_resolution = uint(params.LCDResolution); + + uint slot_x = uint(ModInteger(floor(current_position.x / float(kPhosphorMaskSize[lcd_resolution][crt_resolution])), kMaxSlotSizeX)); + uint slot_y = uint(ModInteger(floor(current_position.y), kMaxSlotSizeY)); + + uint mask = uint(ModInteger(floor(current_position.x), kPhosphorMaskSize[lcd_resolution][crt_resolution])); + + scanline_colour *= kPhosphorMasks[lcd_resolution][crt_resolution][lcd_subpixel_layout][slot_x][slot_y][mask]; + } + + // HACK: To get maximum brightness we just set paper white luminance to max luminance + const vec3 hdr10 = Hdr10(scanline_colour, params.PaperWhiteNits, params.ExpandGamut); + + //FragColor = vec4(scanline_colour, 1.0); + FragColor = vec4(hdr10, 1.0); +} diff --git a/hdr/shaders/crt-sony-pvm-4k-hdr.slang b/hdr/shaders/crt-sony-pvm-4k-hdr.slang deleted file mode 100644 index b4db738..0000000 --- a/hdr/shaders/crt-sony-pvm-4k-hdr.slang +++ /dev/null @@ -1,382 +0,0 @@ -#version 450 - -/* -A shader that tries to emulate a sony PVM type aperture grille screen but with full brightness. - -The novel thing about this shader is that it relies on the HDR shaders to brighten up the image so that when -we apply this shader which emulates the apperture grille the resulting screen isn't left too dark. - -I think you need at least a DisplayHDR 600 monitor but to get close to CRT levels of brightness I think DisplayHDR 1000. - -Please Enable HDR in RetroArch 1.10+ - -NOTE: when this shader is envoked the Contrast, Peak Luminance and Paper White Luminance in the HDR menu do nothing instead set those values through the shader parameters - -For this shader set Peak Luminance AND Paper White Luminance to the peak luminance of your monitor. - -Also try to use a integer scaling - its just better - overscaling is fine. - -This shader doesn't do any geometry warping or bouncing of light around inside the screen etc - I think these effects just add unwanted noise, I know people disagree. Please feel free to make you own and add them - -Dont use this shader directly - use the hdr\crt-sony-pvm-4k-hdr.slangp and variants to have the proper chain of effects. - -THIS SHADER DOES NOT SUPPORT WRGB OLED (Due to the sub pixel layout of WRGB - QD-OLED or LCD (and variants thereof screens are fine) -*/ - -#pragma format A2B10G10R10_UNORM_PACK32 - -#define WHITE_BALANCE_CONTROL 0 - -#include "inverse_tonemap.h" -#include "hdr10.h" - -#if WHITE_BALANCE_CONTROL -//#include "white_balance.h" -#endif // WHITE_BALANCE_CONTROL - -layout(push_constant) uniform Push -{ - // User Settings - float MaxNits; - float LCDResolution; - float LCDSubpixel; - float ExpandGamut; - float RedConvergence; - float GreenConvergence; - float BlueConvergence; - - // Developer Settings - float CRTResolution; - float Contrast; - - // Vertical Settings - float RedScanlineMin; - float RedScanlineMax; - float RedScanlineAttack; - float GreenScanlineMin; - float GreenScanlineMax; - float GreenScanlineAttack; - float BlueScanlineMin; - float BlueScanlineMax; - float BlueScanlineAttack; - - // Horizontal Settings - float RedBeamSharpness; - float RedBeamAttack; - float GreenBeamSharpness; - float GreenBeamAttack; - float BlueBeamSharpness; - float BlueBeamAttack; - -#if WHITE_BALANCE_CONTROL - float WhiteTemperature; - float WhiteTint; -#endif // WHITE_BALANCE_CONTROL -} params; - - -#pragma parameter Title "SONY PVM/BVM HDR SHADER" 0.0 0.0 0.0 0.0 -#pragma parameter Space0 " " 0.0 0.0 0.0 0.0 -#pragma parameter Support0 "SUPPORTED: RGB/BGR LCD, QD-OLED Displays" 0.0 0.0 0.0 0.0 -#pragma parameter Support1 "NOT SUPPORTED: WRGB OLED Displays" 0.0 0.0 0.0 0.0 -#pragma parameter Support2 "MIN SPEC: DisplayHDR 600, 4K" 0.0 0.0 0.0 0.0 -#pragma parameter Support3 "REC SPEC: DisplayHDR 1000, 4K+" 0.0 0.0 0.0 0.0 -#pragma parameter Space1 " " 0.0 0.0 0.0 0.0 -#pragma parameter Instructions0 "HDR: Enable HDR: On" 0.0 0.0 0.0 0.0 -#pragma parameter Instructions1 "SCALING: Integer Scale: ON" 0.0 0.0 0.0 0.0 -#pragma parameter Instructions2 "SCALING: Integer Overscale: ON" 0.0 0.0 0.0 0.0 -#pragma parameter Instructions3 "SCALING: Apect Ratio: Core Provided" 0.0 0.0 0.0 0.0 -#pragma parameter Space2 " " 0.0 0.0 0.0 0.0 -#pragma parameter UserSettings "USER SETTINGS:" 0.0 0.0 0.0 0.0 -#pragma parameter MaxNits " Display's Peak Luminance" 700.0 0.0 10000.0 10.0 -#pragma parameter LCDResolution " Display's Resolution: 4K/8K" 0.0 0.0 1.0 1.0 -#pragma parameter LCDSubpixel " Display's Subpixel Layout: RGB/BGR" 0.0 0.0 1.0 1.0 -#pragma parameter ExpandGamut " Original/Vivid" 0.0 0.0 1.0 1.0 -#pragma parameter RedConvergence " Red Convergence" -0.50 -10.0 10.0 0.05 -#pragma parameter GreenConvergence " Green Convergence" 0.00 -10.0 10.0 0.05 -#pragma parameter BlueConvergence " Blue Convergence" 0.00 -10.0 10.0 0.05 -#pragma parameter Space3 " " 0.0 0.0 0.0 0.0 -#pragma parameter DeveloperSettings "DEVELOPER SETTINGS:" 0.0 0.0 0.0 0.0 -#pragma parameter CRTResolution " CRT Resolution: 600TVL/800TVL/1000TVL" 0.0 0.0 2.0 1.0 -#pragma parameter Contrast " Contrast" -0.3 -3.0 3.0 0.05 -#pragma parameter DeveloperSettings0 " VERTICAL SETTINGS:" 0.0 0.0 0.0 0.0 -#pragma parameter RedScanlineMin " Red Scanline Min" 0.55 0.0 2.0 0.01 -#pragma parameter RedScanlineMax " Red Scanline Max" 0.82 0.0 2.0 0.01 -#pragma parameter RedScanlineAttack " Red Scanline Attack" 0.65 0.0 1.0 0.01 -#pragma parameter GreenScanlineMin " Green Scanline Min" 0.55 0.0 2.0 0.01 -#pragma parameter GreenScanlineMax " Green Scanline Max" 0.90 0.0 2.0 0.01 -#pragma parameter GreenScanlineAttack " Green Scanline Attack" 0.13 0.0 1.0 0.01 -#pragma parameter BlueScanlineMin " Blue Scanline Min" 0.72 0.0 2.0 0.01 -#pragma parameter BlueScanlineMax " Blue Scanline Max" 1.00 0.0 2.0 0.01 -#pragma parameter BlueScanlineAttack " Blue Scanline Attack" 0.65 0.0 1.0 0.01 -#pragma parameter DeveloperSettings1 " HORIZONTAL SETTINGS:" 0.0 0.0 0.0 0.0 -#pragma parameter RedBeamSharpness " Red Beam Sharpness" 1.75 0.0 5.0 0.05 -#pragma parameter RedBeamAttack " Red Beam Attack" 0.72 0.0 1.0 0.01 -#pragma parameter GreenBeamSharpness " Green Beam Sharpness" 1.60 0.0 5.0 0.05 -#pragma parameter GreenBeamAttack " Green Beam Attack" 0.80 0.0 1.0 0.01 -#pragma parameter BlueBeamSharpness " Blue Beam Sharpness" 1.90 0.0 5.0 0.05 -#pragma parameter BlueBeamAttack " Blue Beam Attack" 0.45 0.0 1.0 0.01 - -#if WHITE_BALANCE_CONTROL -//#pragma parameter WhiteTemperature "White Temperature" 6500.0 0.0 13000.0 50.0 -//#pragma parameter WhiteTint "White Tint" 0.0 -1.0 1.0 0.01 -#endif // WHITE_BALANCE_CONTROL - -layout(std140, set = 0, binding = 0) uniform UBO -{ - mat4 MVP; - vec4 SourceSize; - vec4 OriginalSize; - vec4 OutputSize; - uint FrameCount; -} global; - -#pragma stage vertex -layout(location = 0) in vec4 Position; -layout(location = 1) in vec2 TexCoord; -layout(location = 0) out vec2 vTexCoord; -layout(location = 1) out float ScanlineSize; -layout(location = 2) out float InverseScanlineSize; -layout(location = 3) out vec3 Convergence; - -void main() -{ - gl_Position = global.MVP * Position; - vTexCoord = TexCoord * vec2(1.00001); // To resolve rounding issues when sampling - - ScanlineSize = global.OutputSize.y / global.SourceSize.y; - InverseScanlineSize = 1.0f / ScanlineSize; - - Convergence = vec3(params.RedConvergence, params.GreenConvergence, params.BlueConvergence); -} - -#pragma stage fragment -layout(location = 0) in vec2 vTexCoord; -layout(location = 1) in float ScanlineSize; -layout(location = 2) in float InverseScanlineSize; -layout(location = 3) in vec3 Convergence; -layout(location = 0) out vec4 FragColor; -layout(set = 0, binding = 2) uniform sampler2D Source; - -float ModInteger(float a, float b) -{ - float m = a - floor((a + 0.5) / b) * b; - return floor(m + 0.5); -} - -#define kPi 3.1415926536f -#define kEuler 2.718281828459f -#define kMax 1.0f - -#define kLumaRatio 0.5f -#define kBeamWidth 0.5f - -#define kRed vec3(1.0, 0.0, 0.0) -#define kGreen vec3(0.0, 1.0, 0.0) -#define kBlue vec3(0.0, 0.0, 1.0) -#define kMagenta vec3(1.0, 0.0, 1.0) -#define kYellow vec3(1.0, 1.0, 0.0) -#define kCyan vec3(0.0, 1.0, 1.0) -#define kBlack vec3(0.0, 0.0, 0.0) -#define kWhite vec3(1.0, 1.0, 1.0) - -#define kBGRAxis 2 -#define kTVLAxis 3 -#define kResolutionAxis 2 -#define kMaxMaskSize 7 - -#define kNotSupported { kBlack, kBlack, kBlack, kBlack, kBlack, kBlack, kBlack } - -#define kRGBX { kRed, kGreen, kBlue, kBlack, kBlack, kBlack, kBlack } -#define kBGRX { kBlue, kGreen, kRed, kBlack, kBlack, kBlack, kBlack } - -#define kRYCBX { kRed, kYellow, kCyan, kBlue, kBlack, kBlack, kBlack } -#define kBCYRX { kBlue, kCyan, kYellow, kRed, kBlack, kBlack, kBlack } - -#define kRRGGBBX { kRed, kRed, kGreen, kGreen, kBlue, kBlue, kBlack } -#define kBBGGRRX { kBlue, kBlue, kGreen, kGreen, kRed, kRed, kBlack } - -const uint kPhosphorMaskSize [kResolutionAxis][kTVLAxis][kBGRAxis] = { - { // 4K - { 4, 4 }, // 600 TVL - { 1, 1 }, // 800 TVL - { 1, 1 } // 1000 TVL - }, - { // 8K - { 7, 7 }, // 600 TVL - { 5, 5 }, // 800 TVL - { 4, 4 } // 1000 TVL - } -}; - -const vec3 kPhosphorMasks[kResolutionAxis][kTVLAxis][kBGRAxis][kMaxMaskSize] = { - { // 4K - { kRGBX, kBGRX }, // 600 TVL - { kNotSupported, kNotSupported }, // 800 TVL - { kNotSupported, kNotSupported } // 1000 TVL - }, - { // 8K - { kRRGGBBX, kBBGGRRX }, // 600 TVL - { kRYCBX, kRYCBX }, // 800 TVL - { kRGBX, kBGRX } // 1000 TVL - } -}; - -const mat4 kCubicBezier = mat4( 1.0f, 0.0f, 0.0f, 0.0f, - -3.0f, 3.0f, 0.0f, 0.0f, - 3.0f, -6.0f, 3.0f, 0.0f, - -1.0f, 3.0f, -3.0f, 1.0f ); - -const vec4 kFallOffControlPoints = vec4(0.0f, 0.0f, 0.0f, 1.0f); -const vec4 kAttackControlPoints = vec4(0.0f, 1.0f, 1.0f, 1.0f); -//const vec4 kScanlineControlPoints = vec4(1.0f, 1.0f, 0.0f, 0.0f); - -vec4 RedBeamControlPoints(const bool falloff) -{ - return falloff ? kFallOffControlPoints + vec4(0.0f, 0.0f, params.RedBeamAttack, 0.0f) : kAttackControlPoints - vec4(0.0f, params.RedBeamAttack, 0.0f, 0.0f); -} - -vec4 GreenBeamControlPoints(const bool falloff) -{ - return falloff ? kFallOffControlPoints + vec4(0.0f, 0.0f, params.GreenBeamAttack, 0.0f) : kAttackControlPoints - vec4(0.0f, params.GreenBeamAttack, 0.0f, 0.0f); -} - -vec4 BlueBeamControlPoints(const bool falloff) -{ - return falloff ? kFallOffControlPoints + vec4(0.0f, 0.0f, params.BlueBeamAttack, 0.0f) : kAttackControlPoints - vec4(0.0f, params.BlueBeamAttack, 0.0f, 0.0f); -} - -float Bezier(const float t0, const vec4 control_points) -{ - vec4 t = vec4(1.0, t0, t0*t0, t0*t0*t0); - return dot(t, control_points * kCubicBezier); -} - -float ToLinear1(float channel) -{ - return (channel > 0.04045f) ? pow(abs(channel) * (1.0f / 1.055f) + (0.055f / 1.055f), 2.4f) : channel * (1.0f / 12.92f); -} - -vec3 ToLinear(vec3 colour) -{ - return vec3(ToLinear1(colour.r), ToLinear1(colour.g), ToLinear1(colour.b)); -} - -float Contrast1(float linear, float channel) -{ - return (channel > 0.04045f) ? linear * pow(abs(channel) * (1.0f / 1.055f) + (0.055f / 1.055f), params.Contrast) : channel * (1.0f / 12.92f); -} - -vec3 Contrast(vec3 linear, vec3 colour) -{ - return vec3(Contrast1(linear.r, colour.r), Contrast1(linear.g, colour.g), Contrast1(linear.b, colour.b)); -} - -vec3 Ramp(const vec3 luminance, const vec3 colour) -{ - return clamp(luminance * colour, 0.0, 1.0); -} - -vec3 ScanlineColour(const float current_position, const float current_center, const float source_tex_coord_x, const vec3 narrowed_source_pixel_offset, inout float next_prev ) -{ - const float current_source_position_y = (vTexCoord.y * global.SourceSize.y) - next_prev; - const float current_source_center_y = floor(current_source_position_y) + 0.5f; - - const float source_tex_coord_y = current_source_center_y / global.SourceSize.y; - - const vec2 source_tex_coord_0 = vec2(source_tex_coord_x, source_tex_coord_y); - const vec2 source_tex_coord_1 = vec2(source_tex_coord_x + (1.0f / global.SourceSize.x), source_tex_coord_y); - - const float scanline_position = current_source_center_y * ScanlineSize; - const vec3 scanline_delta = vec3(scanline_position) - (vec3(current_center) - Convergence); - - vec3 beam_distance = abs(scanline_delta) - kBeamWidth; - beam_distance = vec3(beam_distance.x < 0.0f ? 0.0f : beam_distance.x, - beam_distance.y < 0.0f ? 0.0f : beam_distance.y, - beam_distance.z < 0.0f ? 0.0f : beam_distance.z); - const vec3 scanline_distance = beam_distance * InverseScanlineSize * 2.0f; - - next_prev = scanline_delta.x > 0.0f ? 1.0f : -1.0f; - - const vec3 sdr_colour_0 = texture(Source, source_tex_coord_0).xyz; - const vec3 sdr_colour_1 = texture(Source, source_tex_coord_1).xyz; - - const vec3 sdr_linear_0 = ToLinear(sdr_colour_0); - const vec3 sdr_linear_1 = ToLinear(sdr_colour_1); - - const vec3 sdr_constrast_0 = Contrast(sdr_linear_0, sdr_colour_0); - const vec3 sdr_constrast_1 = Contrast(sdr_linear_1, sdr_colour_1); - -#if WHITE_BALANCE_CONTROL - //const vec3 sdr_balanced_0 = WhiteBalance(sdr_constrast_0, params.WhiteTemperature, params.WhiteTint); - //const vec3 sdr_balanced_1 = WhiteBalance(sdr_constrast_1, params.WhiteTemperature, params.WhiteTint); -#else - const vec3 sdr_balanced_0 = sdr_constrast_0; - const vec3 sdr_balanced_1 = sdr_constrast_1; -#endif // WHITE_BALANCE_CONTROL - - // HACK: To get maximum brightness we just set paper white luminance to max luminance - const vec3 hdr_colour_0 = InverseTonemap(sdr_balanced_0, params.MaxNits, params.MaxNits, kLumaRatio); - const vec3 hdr_colour_1 = InverseTonemap(sdr_balanced_1, params.MaxNits, params.MaxNits, kLumaRatio); - - /* Horizontal interpolation between pixels */ - const vec3 horiz_interp = vec3(Bezier(narrowed_source_pixel_offset.x, RedBeamControlPoints(sdr_linear_0.x > sdr_linear_1.x)), - Bezier(narrowed_source_pixel_offset.y, GreenBeamControlPoints(sdr_linear_0.y > sdr_linear_1.y)), - Bezier(narrowed_source_pixel_offset.z, BlueBeamControlPoints(sdr_linear_0.z > sdr_linear_1.z))); - - const vec3 hdr_colour = mix(hdr_colour_0, hdr_colour_1, horiz_interp); - const vec3 sdr_colour = mix(sdr_linear_0, sdr_linear_1, horiz_interp); - - const float red_scanline_distance = clamp(scanline_distance.x / ((sdr_colour.r * (params.RedScanlineMax - params.RedScanlineMin)) + params.RedScanlineMin), 0.0f, 1.0f); - const float green_scanline_distance = clamp(scanline_distance.y / ((sdr_colour.g * (params.GreenScanlineMax - params.GreenScanlineMin)) + params.GreenScanlineMin), 0.0f, 1.0f); - const float blue_scanline_distance = clamp(scanline_distance.z / ((sdr_colour.b * (params.BlueScanlineMax - params.BlueScanlineMin)) + params.BlueScanlineMin), 0.0f, 1.0f); - - const vec4 red_control_points = vec4(1.0f, 1.0f, sdr_colour.r * params.RedScanlineAttack, 0.0f); - const vec4 green_control_points = vec4(1.0f, 1.0f, sdr_colour.g * params.GreenScanlineAttack, 0.0f); - const vec4 blue_control_points = vec4(1.0f, 1.0f, sdr_colour.b * params.BlueScanlineAttack, 0.0f); - - const vec3 luminance = vec3(Bezier(red_scanline_distance, red_control_points), - Bezier(green_scanline_distance, green_control_points), - Bezier(blue_scanline_distance, blue_control_points)); - - return luminance * hdr_colour; -} - -void main() -{ - const vec2 current_position = vTexCoord * global.OutputSize.xy; - const float current_center = floor(current_position.y) + 0.5f; - - const float current_source_position_x = vTexCoord.x * global.SourceSize.x; - const float current_source_center_x = floor(current_source_position_x) + 0.5f; - - const float source_tex_coord_x = current_source_center_x / global.SourceSize.x; - - const float source_pixel_offset = current_source_position_x - floor(current_source_position_x); - - const vec3 beam_sharpness = vec3(params.RedBeamSharpness, params.GreenBeamSharpness, params.BlueBeamSharpness); - const vec3 narrowed_source_pixel_offset = clamp(((vec3(source_pixel_offset) - vec3(0.5f)) * beam_sharpness) + vec3(0.5f), vec3(0.0f), vec3(1.0f)); - - float next_prev = 0.0f; - - const vec3 scanline_colour0 = ScanlineColour(current_position.y, current_center, source_tex_coord_x, narrowed_source_pixel_offset, next_prev); - const vec3 scanline_colour1 = ScanlineColour(current_position.y, current_center, source_tex_coord_x, narrowed_source_pixel_offset, next_prev); - - vec3 scanline_colour = scanline_colour0 + scanline_colour1; - - { - uint lcd_subpixel_layout = uint(params.LCDSubpixel); - uint crt_resolution = uint(params.CRTResolution); - uint lcd_resolution = uint(params.LCDResolution); - - uint pattern_x = uint(ModInteger(floor(current_position.x), kPhosphorMaskSize[lcd_resolution][crt_resolution][lcd_subpixel_layout])); - - scanline_colour *= kPhosphorMasks[lcd_resolution][crt_resolution][lcd_subpixel_layout][pattern_x]; - } - - // HACK: To get maximum brightness we just set paper white luminance to max luminance - const vec3 hdr10 = Hdr10(scanline_colour, params.MaxNits, params.ExpandGamut); - - //FragColor = vec4(scanline_colour, 1.0); - FragColor = vec4(hdr10, 1.0); -} diff --git a/hdr/shaders/hdr10.slang b/hdr/shaders/hdr10.slang index 0c7f4e7..94def27 100644 --- a/hdr/shaders/hdr10.slang +++ b/hdr/shaders/hdr10.slang @@ -10,7 +10,7 @@ Originally part of the crt\crt-sony-pvm-4k-hdr.slangp but can be used for any sh #pragma format A2B10G10R10_UNORM_PACK32 -#include "hdr10.h" +#include "include\hdr10.h" layout(push_constant) uniform Push { diff --git a/hdr/shaders/include/developer_parameters.h b/hdr/shaders/include/developer_parameters.h new file mode 100644 index 0000000..347fa3c --- /dev/null +++ b/hdr/shaders/include/developer_parameters.h @@ -0,0 +1,26 @@ + +#pragma parameter Space3 " " 0.0 0.0 0.0 0.0 +#pragma parameter DeveloperSettings "DEVELOPER SETTINGS:" 0.0 0.0 0.0 0.0 +#pragma parameter CRTResolution " CRT Resolution: 600TVL/800TVL/1000TVL" 0.0 0.0 2.0 1.0 +#pragma parameter DeveloperSettings0 " VERTICAL SETTINGS:" 0.0 0.0 0.0 0.0 +#pragma parameter RedScanlineMin " Red Scanline Min" 0.55 0.0 2.0 0.01 +#pragma parameter RedScanlineMax " Red Scanline Max" 0.82 0.0 2.0 0.01 +#pragma parameter RedScanlineAttack " Red Scanline Attack" 0.65 0.0 1.0 0.01 +#pragma parameter GreenScanlineMin " Green Scanline Min" 0.55 0.0 2.0 0.01 +#pragma parameter GreenScanlineMax " Green Scanline Max" 0.90 0.0 2.0 0.01 +#pragma parameter GreenScanlineAttack " Green Scanline Attack" 0.13 0.0 1.0 0.01 +#pragma parameter BlueScanlineMin " Blue Scanline Min" 0.72 0.0 2.0 0.01 +#pragma parameter BlueScanlineMax " Blue Scanline Max" 1.00 0.0 2.0 0.01 +#pragma parameter BlueScanlineAttack " Blue Scanline Attack" 0.65 0.0 1.0 0.01 +#pragma parameter DeveloperSettings1 " HORIZONTAL SETTINGS:" 0.0 0.0 0.0 0.0 +#pragma parameter RedBeamSharpness " Red Beam Sharpness" 1.75 0.0 5.0 0.05 +#pragma parameter RedBeamAttack " Red Beam Attack" 0.72 0.0 1.0 0.01 +#pragma parameter GreenBeamSharpness " Green Beam Sharpness" 1.60 0.0 5.0 0.05 +#pragma parameter GreenBeamAttack " Green Beam Attack" 0.80 0.0 1.0 0.01 +#pragma parameter BlueBeamSharpness " Blue Beam Sharpness" 1.90 0.0 5.0 0.05 +#pragma parameter BlueBeamAttack " Blue Beam Attack" 0.45 0.0 1.0 0.01 + +#if WHITE_BALANCE_CONTROL +//#pragma parameter WhiteTemperature "White Temperature" 6500.0 0.0 13000.0 50.0 +//#pragma parameter WhiteTint "White Tint" 0.0 -1.0 1.0 0.01 +#endif // WHITE_BALANCE_CONTROL diff --git a/hdr/shaders/include/developer_properties.h b/hdr/shaders/include/developer_properties.h new file mode 100644 index 0000000..c556afe --- /dev/null +++ b/hdr/shaders/include/developer_properties.h @@ -0,0 +1,28 @@ + + + // Developer Settings + float CRTResolution; + + // Vertical Settings + float RedScanlineMin; + float RedScanlineMax; + float RedScanlineAttack; + float GreenScanlineMin; + float GreenScanlineMax; + float GreenScanlineAttack; + float BlueScanlineMin; + float BlueScanlineMax; + float BlueScanlineAttack; + + // Horizontal Settings + float RedBeamSharpness; + float RedBeamAttack; + float GreenBeamSharpness; + float GreenBeamAttack; + float BlueBeamSharpness; + float BlueBeamAttack; + +#if WHITE_BALANCE_CONTROL + float WhiteTemperature; + float WhiteTint; +#endif // WHITE_BALANCE_CONTROL \ No newline at end of file diff --git a/hdr/shaders/hdr10.h b/hdr/shaders/include/hdr10.h similarity index 100% rename from hdr/shaders/hdr10.h rename to hdr/shaders/include/hdr10.h diff --git a/hdr/shaders/inverse_tonemap.h b/hdr/shaders/include/inverse_tonemap.h similarity index 100% rename from hdr/shaders/inverse_tonemap.h rename to hdr/shaders/include/inverse_tonemap.h diff --git a/hdr/shaders/include/scanline_generation.h b/hdr/shaders/include/scanline_generation.h new file mode 100644 index 0000000..bdbd826 --- /dev/null +++ b/hdr/shaders/include/scanline_generation.h @@ -0,0 +1,151 @@ + +#include "inverse_tonemap.h" + +#define kPi 3.1415926536f +#define kEuler 2.718281828459f +#define kMax 1.0f + +#define kLumaRatio 0.5f +#define kBeamWidth 0.5f + +const mat4 kCubicBezier = mat4( 1.0f, 0.0f, 0.0f, 0.0f, + -3.0f, 3.0f, 0.0f, 0.0f, + 3.0f, -6.0f, 3.0f, 0.0f, + -1.0f, 3.0f, -3.0f, 1.0f ); + +const vec4 kFallOffControlPoints = vec4(0.0f, 0.0f, 0.0f, 1.0f); +const vec4 kAttackControlPoints = vec4(0.0f, 1.0f, 1.0f, 1.0f); +//const vec4 kScanlineControlPoints = vec4(1.0f, 1.0f, 0.0f, 0.0f); + +vec4 RedBeamControlPoints(const bool falloff) +{ + return falloff ? kFallOffControlPoints + vec4(0.0f, 0.0f, params.RedBeamAttack, 0.0f) : kAttackControlPoints - vec4(0.0f, params.RedBeamAttack, 0.0f, 0.0f); +} + +vec4 GreenBeamControlPoints(const bool falloff) +{ + return falloff ? kFallOffControlPoints + vec4(0.0f, 0.0f, params.GreenBeamAttack, 0.0f) : kAttackControlPoints - vec4(0.0f, params.GreenBeamAttack, 0.0f, 0.0f); +} + +vec4 BlueBeamControlPoints(const bool falloff) +{ + return falloff ? kFallOffControlPoints + vec4(0.0f, 0.0f, params.BlueBeamAttack, 0.0f) : kAttackControlPoints - vec4(0.0f, params.BlueBeamAttack, 0.0f, 0.0f); +} + +float Bezier(const float t0, const vec4 control_points) +{ + vec4 t = vec4(1.0, t0, t0*t0, t0*t0*t0); + return dot(t, control_points * kCubicBezier); +} + +float ToLinear1(float channel) +{ + return (channel > 0.04045f) ? pow(abs(channel) * (1.0f / 1.055f) + (0.055f / 1.055f), 2.4f) : channel * (1.0f / 12.92f); +} + +vec3 ToLinear(vec3 colour) +{ + return vec3(ToLinear1(colour.r), ToLinear1(colour.g), ToLinear1(colour.b)); +} + +float Contrast1(float linear, float channel) +{ + return (channel > 0.04045f) ? linear * pow(abs(channel) * (1.0f / 1.055f) + (0.055f / 1.055f), params.Contrast) : channel * (1.0f / 12.92f); +} + +vec3 Contrast(vec3 linear, vec3 colour) +{ + return vec3(Contrast1(linear.r, colour.r), Contrast1(linear.g, colour.g), Contrast1(linear.b, colour.b)); +} + +vec3 Ramp(const vec3 luminance, const vec3 colour) +{ + return clamp(luminance * colour, 0.0, 1.0); +} + +vec3 ScanlineColour(const float current_position, const float current_center, const float source_tex_coord_x, const vec3 narrowed_source_pixel_offset, inout float next_prev ) +{ + const float current_source_position_y = (vTexCoord.y * global.SourceSize.y) - next_prev; + const float current_source_center_y = floor(current_source_position_y) + 0.5f; + + const float source_tex_coord_y = current_source_center_y / global.SourceSize.y; + + const vec2 source_tex_coord_0 = vec2(source_tex_coord_x, source_tex_coord_y); + const vec2 source_tex_coord_1 = vec2(source_tex_coord_x + (1.0f / global.SourceSize.x), source_tex_coord_y); + + const float scanline_position = current_source_center_y * ScanlineSize; + const vec3 scanline_delta = vec3(scanline_position) - (vec3(current_center) - Convergence); + + vec3 beam_distance = abs(scanline_delta) - kBeamWidth; + beam_distance = vec3(beam_distance.x < 0.0f ? 0.0f : beam_distance.x, + beam_distance.y < 0.0f ? 0.0f : beam_distance.y, + beam_distance.z < 0.0f ? 0.0f : beam_distance.z); + const vec3 scanline_distance = beam_distance * InverseScanlineSize * 2.0f; + + next_prev = scanline_delta.x > 0.0f ? 1.0f : -1.0f; + + const vec3 sdr_colour_0 = texture(Source, source_tex_coord_0).xyz; + const vec3 sdr_colour_1 = texture(Source, source_tex_coord_1).xyz; + + const vec3 sdr_linear_0 = ToLinear(sdr_colour_0); + const vec3 sdr_linear_1 = ToLinear(sdr_colour_1); + + const vec3 sdr_constrast_0 = Contrast(sdr_linear_0, sdr_colour_0); + const vec3 sdr_constrast_1 = Contrast(sdr_linear_1, sdr_colour_1); + +#if WHITE_BALANCE_CONTROL + //const vec3 sdr_balanced_0 = WhiteBalance(sdr_constrast_0, params.WhiteTemperature, params.WhiteTint); + //const vec3 sdr_balanced_1 = WhiteBalance(sdr_constrast_1, params.WhiteTemperature, params.WhiteTint); +#else + const vec3 sdr_balanced_0 = sdr_constrast_0; + const vec3 sdr_balanced_1 = sdr_constrast_1; +#endif // WHITE_BALANCE_CONTROL + + // HACK: To get maximum brightness we just set paper white luminance to max luminance + const vec3 hdr_colour_0 = InverseTonemap(sdr_balanced_0, params.MaxNits, params.PaperWhiteNits, kLumaRatio); + const vec3 hdr_colour_1 = InverseTonemap(sdr_balanced_1, params.MaxNits, params.PaperWhiteNits, kLumaRatio); + + /* Horizontal interpolation between pixels */ + const vec3 horiz_interp = vec3(Bezier(narrowed_source_pixel_offset.x, RedBeamControlPoints(sdr_linear_0.x > sdr_linear_1.x)), + Bezier(narrowed_source_pixel_offset.y, GreenBeamControlPoints(sdr_linear_0.y > sdr_linear_1.y)), + Bezier(narrowed_source_pixel_offset.z, BlueBeamControlPoints(sdr_linear_0.z > sdr_linear_1.z))); + + const vec3 hdr_colour = mix(hdr_colour_0, hdr_colour_1, horiz_interp); + const vec3 sdr_colour = mix(sdr_linear_0, sdr_linear_1, horiz_interp); + + const float red_scanline_distance = clamp(scanline_distance.x / ((sdr_colour.r * (params.RedScanlineMax - params.RedScanlineMin)) + params.RedScanlineMin), 0.0f, 1.0f); + const float green_scanline_distance = clamp(scanline_distance.y / ((sdr_colour.g * (params.GreenScanlineMax - params.GreenScanlineMin)) + params.GreenScanlineMin), 0.0f, 1.0f); + const float blue_scanline_distance = clamp(scanline_distance.z / ((sdr_colour.b * (params.BlueScanlineMax - params.BlueScanlineMin)) + params.BlueScanlineMin), 0.0f, 1.0f); + + const vec4 red_control_points = vec4(1.0f, 1.0f, sdr_colour.r * params.RedScanlineAttack, 0.0f); + const vec4 green_control_points = vec4(1.0f, 1.0f, sdr_colour.g * params.GreenScanlineAttack, 0.0f); + const vec4 blue_control_points = vec4(1.0f, 1.0f, sdr_colour.b * params.BlueScanlineAttack, 0.0f); + + const vec3 luminance = vec3(Bezier(red_scanline_distance, red_control_points), + Bezier(green_scanline_distance, green_control_points), + Bezier(blue_scanline_distance, blue_control_points)); + + return luminance * hdr_colour; +} + +vec3 GenerateScanline(const vec2 current_position) +{ + const float current_center = floor(current_position.y) + 0.5f; + + const float current_source_position_x = vTexCoord.x * global.SourceSize.x; + const float current_source_center_x = floor(current_source_position_x) + 0.5f; + + const float source_tex_coord_x = current_source_center_x / global.SourceSize.x; + + const float source_pixel_offset = current_source_position_x - floor(current_source_position_x); + + const vec3 beam_sharpness = vec3(params.RedBeamSharpness, params.GreenBeamSharpness, params.BlueBeamSharpness); + const vec3 narrowed_source_pixel_offset = clamp(((vec3(source_pixel_offset) - vec3(0.5f)) * beam_sharpness) + vec3(0.5f), vec3(0.0f), vec3(1.0f)); + + float next_prev = 0.0f; + + const vec3 scanline_colour0 = ScanlineColour(current_position.y, current_center, source_tex_coord_x, narrowed_source_pixel_offset, next_prev); + const vec3 scanline_colour1 = ScanlineColour(current_position.y, current_center, source_tex_coord_x, narrowed_source_pixel_offset, next_prev); + + return scanline_colour0 + scanline_colour1; +} \ No newline at end of file diff --git a/hdr/shaders/include/user_parameters.h b/hdr/shaders/include/user_parameters.h new file mode 100644 index 0000000..8c7698a --- /dev/null +++ b/hdr/shaders/include/user_parameters.h @@ -0,0 +1,23 @@ + +#pragma parameter Title "SONY PVM/BVM HDR SHADER" 0.0 0.0 0.0 0.0 +#pragma parameter Space0 " " 0.0 0.0 0.0 0.0 +#pragma parameter Support0 "SUPPORTED: RGB/BGR LCD, QD-OLED Displays" 0.0 0.0 0.0 0.0 +#pragma parameter Support1 "NOT SUPPORTED: WRGB OLED Displays" 0.0 0.0 0.0 0.0 +#pragma parameter Support2 "MIN SPEC: DisplayHDR 600, 4K, RetroArch v1.10" 0.0 0.0 0.0 0.0 +#pragma parameter Support3 "REC SPEC: DisplayHDR 1000, 4K+, RetroArch v1.10" 0.0 0.0 0.0 0.0 +#pragma parameter Space1 " " 0.0 0.0 0.0 0.0 +#pragma parameter Instructions0 "HDR: Enable HDR: On" 0.0 0.0 0.0 0.0 +#pragma parameter Instructions1 "SCALING: Integer Scale: ON" 0.0 0.0 0.0 0.0 +#pragma parameter Instructions2 "SCALING: Integer Overscale: ON" 0.0 0.0 0.0 0.0 +#pragma parameter Instructions3 "SCALING: Apect Ratio: Core Provided" 0.0 0.0 0.0 0.0 +#pragma parameter Space2 " " 0.0 0.0 0.0 0.0 +#pragma parameter UserSettings "USER SETTINGS:" 0.0 0.0 0.0 0.0 +#pragma parameter MaxNits " Display's Peak Luminance" 700.0 0.0 10000.0 10.0 +#pragma parameter PaperWhiteNits " Display's Paper White Luminance" 700.0 0.0 10000.0 10.0 +#pragma parameter LCDResolution " Display's Resolution: 4K/8K" 0.0 0.0 1.0 1.0 +#pragma parameter LCDSubpixel " Display's Subpixel Layout: RGB/BGR" 0.0 0.0 1.0 1.0 +#pragma parameter Contrast " Contrast" -0.3 -3.0 3.0 0.05 +#pragma parameter ExpandGamut " Original/Vivid" 0.0 0.0 1.0 1.0 +#pragma parameter RedConvergence " Red Convergence" -0.50 -10.0 10.0 0.05 +#pragma parameter GreenConvergence " Green Convergence" 0.00 -10.0 10.0 0.05 +#pragma parameter BlueConvergence " Blue Convergence" 0.00 -10.0 10.0 0.05 \ No newline at end of file diff --git a/hdr/shaders/include/user_properties.h b/hdr/shaders/include/user_properties.h new file mode 100644 index 0000000..ce70951 --- /dev/null +++ b/hdr/shaders/include/user_properties.h @@ -0,0 +1,12 @@ + + // User Settings + float MaxNits; + float PaperWhiteNits; + float LCDResolution; + float LCDSubpixel; + float Contrast; + float ExpandGamut; + float RedConvergence; + float GreenConvergence; + float BlueConvergence; + \ No newline at end of file diff --git a/hdr/shaders/inverse_tonemap.slang b/hdr/shaders/inverse_tonemap.slang index 1514006..bfed3e4 100644 --- a/hdr/shaders/inverse_tonemap.slang +++ b/hdr/shaders/inverse_tonemap.slang @@ -10,7 +10,7 @@ Originally part of the crt\crt-sony-pvm-4k-hdr.slangp but can be used for any sh #pragma format R16G16B16A16_SFLOAT -#include "inverse_tonemap.h" +#include "include\inverse_tonemap.h" layout(push_constant) uniform Push {