mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-30 03:11:31 +11:00
184 lines
6.8 KiB
Plaintext
184 lines
6.8 KiB
Plaintext
#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);
|
|
}
|