diff options
author | 2018-10-07 08:42:30 -0700 | |
---|---|---|
committer | 2018-10-07 11:42:30 -0400 | |
commit | b5a54b761c94c543ce950dee0bc4aa0610ba8cba (patch) | |
tree | 9593e366a3f3da82074dec2b431c3dc8ada08d1c /hlsl | |
parent | 7b42e2f79950adc1dd6d3c07df5513eda87b507c (diff) |
HLSL Color Transforms and 3D LUT (#4043)
* Remove broken scanline uniform from post_pass
* Add 3D LUT to HLSL
* Allow individual LUTs for screen and UI
* WIP: Port 3D LUT to BGFX
* Finish porting LUT to BGFX
* Add individual phosphor color conversion for HLSL
new file: hlsl/chroma.fx
Shader for converting xyY3 to sRGB
modified: hlsl/phosphor.fx
Minor changes to emphasize idea that phosphors are color
agnostic
modified: hlsl/post.fx
Conversion from signal RGB to xyY3
modified: src/osd/modules/render/d3d/d3dhlsl.cpp
modified: src/osd/modules/render/d3d/d3dhlsl.h
modified: src/osd/windows/winmain.cpp
modified: src/osd/windows/winmain.h
* Add phosphor examples and update presets
* Port phosphor color shaders to BGFX
* Fix missing newlines at EOF
Diffstat (limited to 'hlsl')
-rw-r--r-- | hlsl/chroma.fx | 122 | ||||
-rw-r--r-- | hlsl/phosphor.fx | 41 | ||||
-rw-r--r-- | hlsl/post.fx | 122 | ||||
-rw-r--r-- | hlsl/primary.fx | 51 |
4 files changed, 258 insertions, 78 deletions
diff --git a/hlsl/chroma.fx b/hlsl/chroma.fx new file mode 100644 index 00000000000..dbb05bfc043 --- /dev/null +++ b/hlsl/chroma.fx @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:W. M. Martinez +//----------------------------------------------------------------------------- +// Phosphor Chromaticity to sRGB Transform Effect +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Sampler Definitions +//----------------------------------------------------------------------------- + +texture Diffuse; + +sampler DiffuseSampler = sampler_state +{ + Texture = <Diffuse>; + MipFilter = LINEAR; + MinFilter = LINEAR; + MagFilter = LINEAR; + AddressU = CLAMP; + AddressV = CLAMP; + AddressW = CLAMP; +}; + +//----------------------------------------------------------------------------- +// Vertex Definitions +//----------------------------------------------------------------------------- + +struct VS_OUTPUT +{ + float4 Position : POSITION; + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; + float2 PrevCoord : TEXCOORD1; +}; + +struct VS_INPUT +{ + float3 Position : POSITION; + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; +}; + +struct PS_INPUT +{ + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; + float2 PrevCoord : TEXCOORD1; +}; + +//----------------------------------------------------------------------------- +// Chroma Vertex Shader +//----------------------------------------------------------------------------- + +uniform float2 ScreenDims; +uniform float2 TargetDims; + +uniform bool Passthrough; + +VS_OUTPUT vs_main(VS_INPUT Input) +{ + VS_OUTPUT Output = (VS_OUTPUT)0.0; + + Output.Position = float4(Input.Position.xyz, 1.0); + Output.Position.xy /= ScreenDims; + Output.Position.y = 1.0 - Output.Position.y; // flip y + Output.Position.xy -= 0.5; // center + Output.Position.xy *= 2.0; // zoom + + Output.TexCoord = Input.TexCoord; + Output.TexCoord += 0.5 / TargetDims; // half texel offset correction (DX9) + + Output.PrevCoord = Output.TexCoord; + + Output.Color = Input.Color; + + return Output; +} + +//----------------------------------------------------------------------------- +// Chroma Pixel Shader +//----------------------------------------------------------------------------- + +uniform float3 YGain = float3(0.2126, 0.7152, 0.0722); +uniform float2 ChromaA = float2(0.630, 0.340); +uniform float2 ChromaB = float2(0.310, 0.595); +uniform float2 ChromaC = float2(0.155, 0.070); + +static const float3x3 XYZ_TO_sRGB = { + 3.2406, -1.5372, -0.4986, + -0.9689, 1.8758, 0.0415, + 0.0557, -0.2040, 1.0570 +}; + +float4 ps_main(PS_INPUT Input) : COLOR +{ + const float4 cin = tex2D(DiffuseSampler, Input.TexCoord); + float4 cout = float4(0.0, 0.0, 0.0, cin.a); + const float3x2 xy = { ChromaA, ChromaB, ChromaC }; + + for (int i = 0; i < 3; ++i) { + const float Y = YGain[i] * cin[i]; + const float X = xy[i].x * (Y / xy[i].y); + const float Z = (1.0 - xy[i].x - xy[i].y) * (Y / xy[i].y); + cout.rgb += mul(XYZ_TO_sRGB, float3(X, Y, Z)); + } + return cout; +} + +//----------------------------------------------------------------------------- +// Phosphor Technique +//----------------------------------------------------------------------------- + +technique DefaultTechnique +{ + pass Pass0 + { + Lighting = FALSE; + + VertexShader = compile vs_2_0 vs_main(); + PixelShader = compile ps_2_0 ps_main(); + } +} diff --git a/hlsl/phosphor.fx b/hlsl/phosphor.fx index d78473a2c6e..e195f34764d 100644 --- a/hlsl/phosphor.fx +++ b/hlsl/phosphor.fx @@ -71,16 +71,16 @@ uniform bool Passthrough; VS_OUTPUT vs_main(VS_INPUT Input) { - VS_OUTPUT Output = (VS_OUTPUT)0; + VS_OUTPUT Output = (VS_OUTPUT)0.0; - Output.Position = float4(Input.Position.xyz, 1.0f); + Output.Position = float4(Input.Position.xyz, 1.0); Output.Position.xy /= ScreenDims; - Output.Position.y = 1.0f - Output.Position.y; // flip y - Output.Position.xy -= 0.5f; // center - Output.Position.xy *= 2.0f; // zoom + Output.Position.y = 1.0 - Output.Position.y; // flip y + Output.Position.xy -= 0.5; // center + Output.Position.xy *= 2.0; // zoom Output.TexCoord = Input.TexCoord; - Output.TexCoord += 0.5f / TargetDims; // half texel offset correction (DX9) + Output.TexCoord += 0.5 / TargetDims; // half texel offset correction (DX9) Output.PrevCoord = Output.TexCoord; @@ -93,24 +93,23 @@ VS_OUTPUT vs_main(VS_INPUT Input) // Phosphor Pixel Shader //----------------------------------------------------------------------------- -uniform float3 Phosphor = float3(0.0f, 0.0f, 0.0f); -uniform float DeltaTime = 0.0f; -static const float F = 30.0f; +uniform float DeltaTime = 0.0; +uniform float3 Phosphor = float3(0.0, 0.0, 0.0); + +static const float F = 30.0; float4 ps_main(PS_INPUT Input) : COLOR { - float4 CurrPix = tex2D(DiffuseSampler, Input.TexCoord); - float3 PrevPix = tex2D(PreviousSampler, Input.PrevCoord).rgb; - - PrevPix.r *= Phosphor.r == 0 ? 0 : pow(Phosphor.r, F * DeltaTime); - PrevPix.g *= Phosphor.g == 0 ? 0 : pow(Phosphor.g, F * DeltaTime); - PrevPix.b *= Phosphor.b == 0 ? 0 : pow(Phosphor.b, F * DeltaTime); - float RedMax = max(CurrPix.r, PrevPix.r); - float GreenMax = max(CurrPix.g, PrevPix.g); - float BlueMax = max(CurrPix.b, PrevPix.b); - - return Passthrough ? - CurrPix : float4(RedMax, GreenMax, BlueMax, CurrPix.a); + float4 CurrY = tex2D(DiffuseSampler, Input.TexCoord); + float3 PrevY = tex2D(PreviousSampler, Input.PrevCoord).rgb; + + PrevY[0] *= Phosphor[0] == 0.0 ? 0.0 : pow(Phosphor[0], F * DeltaTime); + PrevY[1] *= Phosphor[1] == 0.0 ? 0.0 : pow(Phosphor[1], F * DeltaTime); + PrevY[2] *= Phosphor[2] == 0.0 ? 0.0 : pow(Phosphor[2], F * DeltaTime); + float a = max(PrevY[0], CurrY[0]); + float b = max(PrevY[1], CurrY[1]); + float c = max(PrevY[2], CurrY[2]); + return Passthrough ? CurrY : float4(a, b, c, CurrY.a); } //----------------------------------------------------------------------------- diff --git a/hlsl/post.fx b/hlsl/post.fx index 0d3bf244a16..ed9dfff9e30 100644 --- a/hlsl/post.fx +++ b/hlsl/post.fx @@ -4,6 +4,10 @@ // Shadowmask Effect //----------------------------------------------------------------------------- +#define MONOCHROME 1 +#define DICHROME 2 +#define TRICHROME 3 + //----------------------------------------------------------------------------- // Sampler Definitions //----------------------------------------------------------------------------- @@ -64,8 +68,8 @@ struct PS_INPUT // Constants //----------------------------------------------------------------------------- -static const float PI = 3.1415927f; -static const float HalfPI = PI * 0.5f; +static const float PI = 3.1415927; +static const float HalfPI = PI * 0.5; //----------------------------------------------------------------------------- // Shadowmask Vertex Shader @@ -77,8 +81,8 @@ uniform float2 TargetDims; uniform float2 TargetScale; uniform float2 QuadDims; -uniform float2 ShadowDims = float2(32.0f, 32.0f); // size of the shadow texture (extended to power-of-two size) -uniform float2 ShadowUVOffset = float2(0.0f, 0.0f); +uniform float2 ShadowDims = float2(32.0, 32.0); // size of the shadow texture (extended to power-of-two size) +uniform float2 ShadowUVOffset = float2(0.0, 0.0); uniform bool SwapXY = false; @@ -89,16 +93,16 @@ VS_OUTPUT vs_main(VS_INPUT Input) { VS_OUTPUT Output = (VS_OUTPUT)0; - Output.Position = float4(Input.Position.xyz, 1.0f); + Output.Position = float4(Input.Position.xyz, 1.0); Output.Position.xy /= ScreenDims; - Output.Position.y = 1.0f - Output.Position.y; // flip y - Output.Position.xy -= 0.5f; // center - Output.Position.xy *= 2.0f; // zoom + Output.Position.y = 1.0 - Output.Position.y; // flip y + Output.Position.xy -= 0.5; // center + Output.Position.xy *= 2.0; // zoom Output.TexCoord = Input.TexCoord; Output.TexCoord += PrepareBloom - ? 0.0f // use half texel offset (DX9) to do the blur for first bloom layer - : 0.5f / TargetDims; // fix half texel offset (DX9) + ? 0.0 // use half texel offset (DX9) to do the blur for first bloom layer + : 0.5 / TargetDims; // fix half texel offset (DX9) Output.ScreenCoord = Input.Position.xy / ScreenDims; @@ -111,34 +115,37 @@ VS_OUTPUT vs_main(VS_INPUT Input) // Shadowmask Pixel Shader //----------------------------------------------------------------------------- -uniform float HumBarDesync = 60.0f / 59.94f - 1.0f; // difference between the 59.94 Hz field rate and 60 Hz line frequency (NTSC) -uniform float HumBarAlpha = 0.0f; +uniform float HumBarDesync = 60.0 / 59.94 - 1.0; // difference between the 59.94 Hz field rate and 60 Hz line frequency (NTSC) +uniform float HumBarAlpha = 0.0; -uniform float TimeMilliseconds = 0.0f; +uniform float TimeMilliseconds = 0.0; -uniform float2 ScreenScale = float2(1.0f, 1.0f); -uniform float2 ScreenOffset = float2(0.0f, 0.0f); +uniform float2 ScreenScale = float2(1.0, 1.0); +uniform float2 ScreenOffset = float2(0.0, 0.0); -uniform float3 BackColor = float3(0.0f, 0.0f, 0.0f); +uniform float3 BackColor = float3(0.0, 0.0, 0.0); uniform int ShadowTileMode = 0; // 0 based on screen (quad) dimension, 1 based on source dimension -uniform float ShadowAlpha = 0.0f; -uniform float2 ShadowCount = float2(6.0f, 6.0f); -uniform float2 ShadowUV = float2(0.25f, 0.25f); +uniform float ShadowAlpha = 0.0; +uniform float2 ShadowCount = float2(6.0, 6.0); +uniform float2 ShadowUV = float2(0.25, 0.25); + +uniform float3 Power = float3(1.0, 1.0, 1.0); +uniform float3 Floor = float3(0.0, 0.0, 0.0); -uniform float3 Power = float3(1.0f, 1.0f, 1.0f); -uniform float3 Floor = float3(0.0f, 0.0f, 0.0f); +uniform int ChromaMode = 3; +uniform float3 ConversionGain = float3(0.0, 0.0, 0.0); float2 GetAdjustedCoords(float2 coord) { // center coordinates - coord -= 0.5f; + coord -= 0.5; // apply screen scale coord *= ScreenScale; // un-center coordinates - coord += 0.5f; + coord += 0.5; // apply screen offset coord += ScreenOffset; @@ -158,8 +165,8 @@ float2 GetShadowCoord(float2 TargetCoord, float2 SourceCoord) ? TargetCoord + ShadowUVOffset / BaseTargetDims : SourceCoord + ShadowUVOffset / SourceDims; float2 canvasTexelDims = ShadowTileMode == 0 - ? 1.0f / BaseTargetDims - : 1.0f / SourceDims; + ? 1.0 / BaseTargetDims + : 1.0 / SourceDims; float2 shadowDims = ShadowDims; float2 shadowUV = ShadowUV; @@ -186,8 +193,8 @@ float2 GetShadowCoord(float2 TargetCoord, float2 SourceCoord) float2 shadowCoord = (shadowFrac * shadowUV); shadowCoord += ShadowTileMode == 0 - ? 0.5f / shadowDims // fix half texel offset (DX9) - : 0.0f; + ? 0.5 / shadowDims // fix half texel offset (DX9) + : 0.0; return shadowCoord; } @@ -199,29 +206,14 @@ float4 ps_main(PS_INPUT Input) : COLOR // Color float4 BaseColor = tex2D(DiffuseSampler, BaseCoord); - BaseColor.a = 1.0f; + BaseColor.a = 1.0; // clip border - if (BaseCoord.x < 0.0f || BaseCoord.y < 0.0f || - BaseCoord.x > 1.0f || BaseCoord.y > 1.0f) + if (BaseCoord.x < 0.0 || BaseCoord.y < 0.0 || + BaseCoord.x > 1.0 || BaseCoord.y > 1.0) { // we don't use the clip function, because we don't clear the render target before - return float4(0.0f, 0.0f, 0.0f, 1.0f); - } - - // Mask Simulation (may not affect bloom) - if (!PrepareBloom && ShadowAlpha > 0.0f) - { - float2 ShadowCoord = GetShadowCoord(ScreenCoord, BaseCoord); - - float4 ShadowColor = tex2D(ShadowSampler, ShadowCoord); - float3 ShadowMaskColor = lerp(1.0f, ShadowColor.rgb, ShadowAlpha); - float ShadowMaskClear = (1.0f - ShadowColor.a) * ShadowAlpha; - - // apply shadow mask color - BaseColor.rgb *= ShadowMaskColor; - // clear shadow mask by background color - BaseColor.rgb = lerp(BaseColor.rgb, BackColor, ShadowMaskClear); + return float4(0.0, 0.0, 0.0, 1.0); } // Color Compression (may not affect bloom) @@ -236,16 +228,36 @@ float4 ps_main(PS_INPUT Input) : COLOR BaseColor.g = pow(BaseColor.g, Power.g); BaseColor.b = pow(BaseColor.b, Power.b); - // Scanline Simulation (may not affect bloom) - if (!PrepareBloom) + // Hum Bar Simulation (may not affect vector screen) + if (!PrepareBloom && !VectorScreen && HumBarAlpha > 0.0) { - // Hum Bar Simulation (may not affect vector screen) - if (!VectorScreen && HumBarAlpha > 0.0f) - { - float HumBarStep = frac(TimeMilliseconds * HumBarDesync); - float HumBarBrightness = 1.0 - frac(BaseCoord.y + HumBarStep) * HumBarAlpha; - BaseColor.rgb *= HumBarBrightness; - } + float HumBarStep = frac(TimeMilliseconds * HumBarDesync); + float HumBarBrightness = 1.0 - frac(BaseCoord.y + HumBarStep) * HumBarAlpha; + BaseColor.rgb *= HumBarBrightness; + } + + // Mask Simulation (may not affect bloom) + if (!PrepareBloom && ShadowAlpha > 0.0) + { + float2 ShadowCoord = GetShadowCoord(ScreenCoord, BaseCoord); + + float4 ShadowColor = tex2D(ShadowSampler, ShadowCoord); + float3 ShadowMaskColor = lerp(1.0, ShadowColor.rgb, ShadowAlpha); + float ShadowMaskClear = (1.0 - ShadowColor.a) * ShadowAlpha; + + // apply shadow mask color + BaseColor.rgb *= ShadowMaskColor; + // clear shadow mask by background color + BaseColor.rgb = lerp(BaseColor.rgb, BackColor, ShadowMaskClear); + } + + // Preparation for phosphor color conversion + if (ChromaMode == MONOCHROME) { + BaseColor.r = dot(ConversionGain, BaseColor.rgb); + BaseColor.gb = float2(BaseColor.r, BaseColor.r); + } else if (ChromaMode == DICHROME) { + BaseColor.r = dot(ConversionGain.rg, BaseColor.rg); + BaseColor.g = BaseColor.r; } return BaseColor; diff --git a/hlsl/primary.fx b/hlsl/primary.fx index 839ebbf8bf0..998a4b8716a 100644 --- a/hlsl/primary.fx +++ b/hlsl/primary.fx @@ -1,14 +1,23 @@ // license:BSD-3-Clause -// copyright-holders:Ryan Holtz +// copyright-holders:Ryan Holtz, W. M. Martinez //----------------------------------------------------------------------------- // Primary Effect //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- + +#define LUT_TEXTURE_WIDTH 4096.0f +#define LUT_SIZE 64.0f +#define LUT_SCALE float2(1.0f / LUT_TEXTURE_WIDTH, 1.0f / LUT_SIZE) + +//----------------------------------------------------------------------------- // Sampler Definitions //----------------------------------------------------------------------------- texture Diffuse; +texture LutTexture; sampler DiffuseSampler = sampler_state { @@ -21,6 +30,35 @@ sampler DiffuseSampler = sampler_state AddressW = CLAMP; }; +sampler2D LutSampler = sampler_state +{ + Texture = <LutTexture>; + MinFilter = LINEAR; + MagFilter = LINEAR; + MipFilter = LINEAR; + AddressU = CLAMP; + AddressV = CLAMP; + AddressW = CLAMP; +}; + +//----------------------------------------------------------------------------- +// Utilities +//----------------------------------------------------------------------------- + +float3 apply_lut(float3 color) +{ + // NOTE: Do not change the order of parameters here. + float3 lutcoord = float3((color.rg * (LUT_SIZE - 1.0f) + 0.5f) * + LUT_SCALE, color.b * (LUT_SIZE - 1.0f)); + float shift = floor(lutcoord.z); + + lutcoord.x += shift * LUT_SCALE.y; + color.rgb = lerp(tex2D(LutSampler, lutcoord.xy).rgb, tex2D(LutSampler, + float2(lutcoord.x + LUT_SCALE.y, lutcoord.y)).rgb, + lutcoord.z - shift); + return color; +} + //----------------------------------------------------------------------------- // Vertex Definitions //----------------------------------------------------------------------------- @@ -49,7 +87,7 @@ struct PS_INPUT // Primary Vertex Shaders //----------------------------------------------------------------------------- -static const float Epsilon = 1.0e-7f; +//static const float Epsilon = 1.0e-7f; uniform float2 ScreenDims; uniform float2 TargetDims; @@ -112,10 +150,15 @@ VS_OUTPUT vs_ui_main(VS_INPUT Input) // Primary Pixel Shaders //----------------------------------------------------------------------------- +uniform bool LutEnable; +uniform bool UiLutEnable; + float4 ps_screen_main(PS_INPUT Input) : COLOR { float4 BaseTexel = tex2D(DiffuseSampler, Input.TexCoord); + if (LutEnable) + BaseTexel.rgb = apply_lut(BaseTexel.rgb); return BaseTexel; } @@ -123,6 +166,8 @@ float4 ps_vector_buffer_main(PS_INPUT Input) : COLOR { float4 BaseTexel = tex2D(DiffuseSampler, Input.TexCoord); + if (LutEnable) + BaseTexel.rgb = apply_lut(BaseTexel.rgb); return BaseTexel; } @@ -131,6 +176,8 @@ float4 ps_ui_main(PS_INPUT Input) : COLOR float4 BaseTexel = tex2D(DiffuseSampler, Input.TexCoord); BaseTexel *= Input.Color; + if (UiLutEnable) + BaseTexel.rgb = apply_lut(BaseTexel.rgb); return BaseTexel; } |