HLSL Updates: [Ryan Holtz, Bat Country Entertainment, austere]

- Reworked default shadow mask settings, eliminating rainbow banding and matching reference shots more closely
- Moved color power to occur after shadow mask, as it is intended to simulate nonlinear phosphor response
- Added a variable-width notch filter to the Y channel in NTSC post-processing, eliminating luma banding on e.g. CoCo 2 and Apple II
This commit is contained in:
Ryan Holtz 2011-06-06 21:25:38 +00:00
parent 1d33744bd4
commit 1ec454197a
7 changed files with 42 additions and 29 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 271 B

View file

@ -100,10 +100,6 @@ uniform float BluFloor = 0.0f;
uniform float Saturation = 1.0f;
uniform float RedPower = 2.2f;
uniform float GrnPower = 2.2f;
uniform float BluPower = 2.2f;
float4 ps_main(PS_INPUT Input) : COLOR
{
float4 BaseTexel = tex2D(DiffuseSampler, Input.TexCoord);
@ -126,10 +122,6 @@ float4 ps_main(PS_INPUT Input) : COLOR
float3 OutChroma = OutTexel - OutLuma;
float3 Saturated = OutLuma + OutChroma * Saturation;
OutRGB.r = pow(Saturated.r, RedPower);
OutRGB.g = pow(Saturated.g, GrnPower);
OutRGB.b = pow(Saturated.b, BluPower);
return float4(OutRGB, BaseTexel.a);
}

View file

@ -119,6 +119,10 @@ uniform float BluFloor = 0.0f;
uniform float SnapX = 0.0f;
uniform float SnapY = 0.0f;
uniform float RedPower = 2.2f;
uniform float GrnPower = 2.2f;
uniform float BluPower = 2.2f;
float4 ps_main(PS_INPUT Input) : COLOR
{
float2 Ratios = float2(WidthRatio, HeightRatio);
@ -174,13 +178,17 @@ float4 ps_main(PS_INPUT Input) : COLOR
float2 ShadowDims = float2(ShadowWidth, ShadowHeight);
float2 ShadowUV = float2(ShadowU, ShadowV);
float2 ShadowMaskSize = float2(ShadowMaskSizeX, ShadowMaskSizeY);
float2 ShadowFrac = frac(BaseCoord * ShadowMaskSize * 0.5f);
float2 ShadowFrac = frac(BaseCoord * ShadowMaskSize);
float2 ShadowCoord = ShadowFrac * ShadowUV + float2(1.5f / ShadowWidth, 1.5f / ShadowHeight);
float3 ShadowTexel = lerp(1.0f, tex2D(ShadowSampler, ShadowCoord).rgb, UseShadow);
// -- Final Pixel --
float4 Output = float4(Scanned * lerp(1.0f, ShadowTexel, ShadowBrightness), BaseTexel.a) * Input.Color;
Output.r = pow(Output.r, RedPower);
Output.g = pow(Output.g, GrnPower);
Output.b = pow(Output.b, BluPower);
return Output;
}

View file

@ -91,7 +91,8 @@ uniform float PValue = 1.0f;
uniform float OValue = 0.0f;
uniform float ScanTime = 52.6f;
uniform float YFreqResponse = 3.0f;
uniform float NotchHalfWidth = 1.0f;
uniform float YFreqResponse = 6.0f;
uniform float IFreqResponse = 1.2f;
uniform float QFreqResponse = 0.6f;
@ -108,15 +109,17 @@ float4 ps_main(PS_INPUT Input) : COLOR
float MaxC = 2.1183f;
float MinC = -1.1183f;
float CRange = MaxC - MinC;
float Fc_y = YFreqResponse * ScanTime / (RawWidth * 4.0f / WidthRatio);
float Fc_y1 = (CCValue - NotchHalfWidth) * ScanTime / (RawWidth * 4.0f / WidthRatio);
float Fc_y2 = (CCValue + NotchHalfWidth) * ScanTime / (RawWidth * 4.0f / WidthRatio);
float Fc_y3 = YFreqResponse * ScanTime / (RawWidth * 4.0f / WidthRatio);
float Fc_i = IFreqResponse * ScanTime / (RawWidth * 4.0f / WidthRatio);
float Fc_q = QFreqResponse * ScanTime / (RawWidth * 4.0f / WidthRatio);
float PI = 3.1415926535897932384626433832795;
float PI2 = 2.0f * PI;
float PI2Length = PI2 / 42.0f;
float PI2Length = PI2 / 82.0f;
float4 NOffset = float4(0.0f, 1.0f, 2.0f, 3.0f);
float W = PI2 * CCValue * ScanTime;
for(float n = -21.0f; n < 22.0f; n += 4.0f)
for(float n = -41.0f; n < 42.0f; n += 4.0f)
{
float4 n4 = n + NOffset;
float4 CoordX = Input.Coord0.x + Input.Coord0.z * n4 * 0.25f;
@ -125,9 +128,14 @@ float4 ps_main(PS_INPUT Input) : COLOR
float4 C = tex2D(CompositeSampler, TexCoord + float2(0.625f, 0.4f) / RawDims) * CRange + MinC;
float4 WT = W * (CoordX * WidthRatio + AValue * CoordY * 2.0f * (RawHeight / HeightRatio) + BValue) + OValue;
float4 SincYIn = PI2 * Fc_y * n4;
float4 IdealY = 2.0f * Fc_y * ((SincYIn != 0.0f) ? (sin(SincYIn) / SincYIn) : 1.0f);
float4 FilterY = (0.54f + 0.46f * cos(PI2Length * n4)) * IdealY;
float4 SincYIn1 = PI2 * Fc_y1 * n4;
float4 SincYIn2 = PI2 * Fc_y2 * n4;
float4 SincYIn3 = PI2 * Fc_y3 * n4;
float4 SincY1 = ((SincYIn1 != 0.0f) ? (sin(SincYIn1) / SincYIn1) : 1.0f);
float4 SincY2 = ((SincYIn2 != 0.0f) ? (sin(SincYIn2) / SincYIn2) : 1.0f);
float4 SincY3 = ((SincYIn3 != 0.0f) ? (sin(SincYIn3) / SincYIn3) : 1.0f);
float4 IdealY = (2.0f * Fc_y1 * SincY1 - 2.0f * Fc_y2 * SincY2) + 2.0f * Fc_y3 * SincY3;
float4 FilterY = (0.54f + 0.46f * cos(PI2Length * n4)) * IdealY;
float4 SincIIn = PI2 * Fc_i * n4;
float4 IdealI = 2.0f * Fc_i * ((SincIIn != 0.0f) ? (sin(SincIIn) / SincIIn) : 1.0f);

View file

@ -1016,6 +1016,9 @@ void hlsl_info::init_effect_info(d3d_poly_info *poly)
(*d3dintf->effect.set_float)(curr_effect, "ScanlineBrightScale", options->scanline_bright_scale);
(*d3dintf->effect.set_float)(curr_effect, "ScanlineBrightOffset", options->scanline_bright_offset);
(*d3dintf->effect.set_float)(curr_effect, "ScanlineOffset", (poly->texture->cur_frame == 0) ? 0.0f : options->scanline_offset);
(*d3dintf->effect.set_float)(curr_effect, "RedPower", options->red_power);
(*d3dintf->effect.set_float)(curr_effect, "GrnPower", options->green_power);
(*d3dintf->effect.set_float)(curr_effect, "BluPower", options->blue_power);
}
else
{
@ -1062,6 +1065,7 @@ void hlsl_info::render_quad(d3d_poly_info *poly, int vertnum)
(*d3dintf->effect.set_float)(curr_effect, "AValue", winoptions.screen_yiq_a());
(*d3dintf->effect.set_float)(curr_effect, "BValue", (poly->texture->cur_frame == 2) ? 0.0f : ((float)poly->texture->cur_frame * winoptions.screen_yiq_b()));
(*d3dintf->effect.set_float)(curr_effect, "PValue", winoptions.screen_yiq_p());
(*d3dintf->effect.set_float)(curr_effect, "NotchHalfWidth", winoptions.screen_yiq_n());
(*d3dintf->effect.set_float)(curr_effect, "YFreqResponse", winoptions.screen_yiq_y());
(*d3dintf->effect.set_float)(curr_effect, "IFreqResponse", winoptions.screen_yiq_i());
(*d3dintf->effect.set_float)(curr_effect, "QFreqResponse", winoptions.screen_yiq_q());
@ -1102,6 +1106,7 @@ void hlsl_info::render_quad(d3d_poly_info *poly, int vertnum)
(*d3dintf->effect.set_float)(curr_effect, "BValue", (poly->texture->cur_frame == 2) ? 0.0f : ((float)poly->texture->cur_frame * winoptions.screen_yiq_b()));
(*d3dintf->effect.set_float)(curr_effect, "OValue", winoptions.screen_yiq_o());
(*d3dintf->effect.set_float)(curr_effect, "PValue", winoptions.screen_yiq_p());
(*d3dintf->effect.set_float)(curr_effect, "NotchHalfWidth", winoptions.screen_yiq_n());
(*d3dintf->effect.set_float)(curr_effect, "YFreqResponse", winoptions.screen_yiq_y());
(*d3dintf->effect.set_float)(curr_effect, "IFreqResponse", winoptions.screen_yiq_i());
(*d3dintf->effect.set_float)(curr_effect, "QFreqResponse", winoptions.screen_yiq_q());
@ -1156,9 +1161,6 @@ void hlsl_info::render_quad(d3d_poly_info *poly, int vertnum)
(*d3dintf->effect.set_float)(curr_effect, "RedScale", options->red_scale);
(*d3dintf->effect.set_float)(curr_effect, "GrnScale", options->green_scale);
(*d3dintf->effect.set_float)(curr_effect, "BluScale", options->blue_scale);
(*d3dintf->effect.set_float)(curr_effect, "RedPower", options->red_power);
(*d3dintf->effect.set_float)(curr_effect, "GrnPower", options->green_power);
(*d3dintf->effect.set_float)(curr_effect, "BluPower", options->blue_power);
(*d3dintf->effect.set_float)(curr_effect, "Saturation", options->saturation);
HRESULT result = (*d3dintf->device.set_render_target)(d3d->device, 0, smalltarget0[poly->texture->target_index]);

View file

@ -333,14 +333,14 @@ const options_entry windows_options::s_option_entries[] =
{ WINOPTION_HLSL_PRESCALE_SIZE, "3", OPTION_INTEGER, "HLSL scaling pre-pass factor (usually 2 or 3)" },
{ WINOPTION_HLSL_PRESET";(-1-5)", "-1", OPTION_INTEGER, "HLSL preset to use (0-5)" },
{ WINOPTION_HLSL_WRITE, NULL, OPTION_STRING, "enable HLSL AVI writing (huge disk bandwidth suggested)" },
{ WINOPTION_HLSL_SNAP_WIDTH, "2048", OPTION_STRING, "HLSL upscaled-snapshot width" },
{ WINOPTION_HLSL_SNAP_HEIGHT, "1536", OPTION_STRING, "HLSL upscaled-snapshot height" },
{ WINOPTION_HLSL_SNAP_WIDTH, "2048", OPTION_STRING, "HLSL upscaled-snapshot width" },
{ WINOPTION_HLSL_SNAP_HEIGHT, "1536", OPTION_STRING, "HLSL upscaled-snapshot height" },
{ WINOPTION_SHADOW_MASK_ALPHA";fs_shadwa(0.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" },
{ WINOPTION_SHADOW_MASK_TEXTURE";fs_shadwt(0.0-1.0)", "aperture.png", OPTION_STRING, "shadow mask texture name" },
{ WINOPTION_SHADOW_MASK_COUNT_X";fs_shadww", "640", OPTION_INTEGER, "shadow mask width, in phosphor dots" },
{ WINOPTION_SHADOW_MASK_COUNT_Y";fs_shadwh", "480", OPTION_INTEGER, "shadow mask height, in phosphor dots" },
{ WINOPTION_SHADOW_MASK_USIZE";fs_shadwu(0.0-1.0)", "0.1875", OPTION_FLOAT, "shadow mask texture size in U direction" },
{ WINOPTION_SHADOW_MASK_VSIZE";fs_shadwv(0.0-1.0)", "0.1875", OPTION_FLOAT, "shadow mask texture size in V direction" },
{ WINOPTION_SHADOW_MASK_COUNT_X";fs_shadww", "320", OPTION_INTEGER, "shadow mask width, in phosphor dots" },
{ WINOPTION_SHADOW_MASK_COUNT_Y";fs_shadwh", "240", OPTION_INTEGER, "shadow mask height, in phosphor dots" },
{ WINOPTION_SHADOW_MASK_USIZE";fs_shadwu(0.0-1.0)", "0.09375", OPTION_FLOAT, "shadow mask texture size in U direction" },
{ WINOPTION_SHADOW_MASK_VSIZE";fs_shadwv(0.0-1.0)", "0.109375", OPTION_FLOAT, "shadow mask texture size in V direction" },
{ WINOPTION_CURVATURE";fs_curv(0.0-4.0)", "0.0", OPTION_FLOAT, "screen curvature amount" },
{ WINOPTION_SCREEN_SCALE_TOP";fs_scalex(0.0-2.0)", "1.0", OPTION_FLOAT, "screen scale, top" },
{ WINOPTION_SCREEN_SCALE_BOTTOM";fs_scaley(0.0-2.0)", "1.0", OPTION_FLOAT, "screen scale, bottom" },
@ -389,9 +389,9 @@ const options_entry windows_options::s_option_entries[] =
{ WINOPTION_RED_SCALE";fs_redmul(0.0-2.0)", "1.0", OPTION_FLOAT, "red signal scaling value (multiplicative)" },
{ WINOPTION_GREEN_SCALE";fs_grnmul(0.0-2.0)", "1.0", OPTION_FLOAT, "green signal scaling value (multiplicative)" },
{ WINOPTION_BLUE_SCALE";fs_blumul(0.0-2.0)", "1.0", OPTION_FLOAT, "blue signal scaling value (multiplicative)" },
{ WINOPTION_RED_POWER";fs_redpow(0.01-32.0)", "1.0", OPTION_FLOAT, "red signal power value (exponential)" },
{ WINOPTION_GREEN_POWER";fs_grnpow(0.01-32.0)", "1.0", OPTION_FLOAT, "green signal power value (exponential)" },
{ WINOPTION_BLUE_POWER";fs_blupow(0.01-32.0)", "1.0", OPTION_FLOAT, "blue signal power value (exponential)" },
{ WINOPTION_RED_POWER";fs_redpow(0.01-4.0)", "1.0", OPTION_FLOAT, "red signal power value (exponential)" },
{ WINOPTION_GREEN_POWER";fs_grnpow(0.01-4.0)", "1.0", OPTION_FLOAT, "green signal power value (exponential)" },
{ WINOPTION_BLUE_POWER";fs_blupow(0.01-4.0)", "1.0", OPTION_FLOAT, "blue signal power value (exponential)" },
{ WINOPTION_RED_FLOOR";fs_redfl(0.0-1.0)", "0.0", OPTION_FLOAT, "red signal floor level" },
{ WINOPTION_GREEN_FLOOR";fs_grnfl(0.0-1.0)", "0.0", OPTION_FLOAT, "green signal floor level" },
{ WINOPTION_BLUE_FLOOR";fs_blufl(0.0-1.0)", "0.0", OPTION_FLOAT, "blue signal floor level" },
@ -405,7 +405,8 @@ const options_entry windows_options::s_option_entries[] =
{ WINOPTION_YIQ_BVALUE";yiqb", "0.5", OPTION_FLOAT, "B value for NTSC signal processing" },
{ WINOPTION_YIQ_OVALUE";yiqo", "0.0", OPTION_FLOAT, "Outgoing Color Carrier phase offset for NTSC signal processing" },
{ WINOPTION_YIQ_PVALUE";yiqp", "1.0", OPTION_FLOAT, "Incoming Pixel Clock scaling value for NTSC signal processing" },
{ WINOPTION_YIQ_YVALUE";yiqy", "3.0", OPTION_FLOAT, "Y filter cutoff frequency for NTSC signal processing" },
{ WINOPTION_YIQ_NVALUE";yiqn", "1.0", OPTION_FLOAT, "Y filter notch width for NTSC signal processing" },
{ WINOPTION_YIQ_YVALUE";yiqy", "6.0", OPTION_FLOAT, "Y filter cutoff frequency for NTSC signal processing" },
{ WINOPTION_YIQ_IVALUE";yiqi", "1.2", OPTION_FLOAT, "I filter cutoff frequency for NTSC signal processing" },
{ WINOPTION_YIQ_QVALUE";yiqq", "0.6", OPTION_FLOAT, "Q filter cutoff frequency for NTSC signal processing" },
{ WINOPTION_YIQ_SCAN_TIME";yiqsc", "52.6", OPTION_FLOAT, "Horizontal scanline duration for NTSC signal processing (in usec)" },

View file

@ -147,6 +147,7 @@
#define WINOPTION_YIQ_BVALUE "yiq_b"
#define WINOPTION_YIQ_OVALUE "yiq_o"
#define WINOPTION_YIQ_PVALUE "yiq_p"
#define WINOPTION_YIQ_NVALUE "yiq_n"
#define WINOPTION_YIQ_YVALUE "yiq_y"
#define WINOPTION_YIQ_IVALUE "yiq_i"
#define WINOPTION_YIQ_QVALUE "yiq_q"
@ -268,6 +269,7 @@ public:
float screen_yiq_b() const { return float_value(WINOPTION_YIQ_BVALUE); }
float screen_yiq_o() const { return float_value(WINOPTION_YIQ_OVALUE); }
float screen_yiq_p() const { return float_value(WINOPTION_YIQ_PVALUE); }
float screen_yiq_n() const { return float_value(WINOPTION_YIQ_NVALUE); }
float screen_yiq_y() const { return float_value(WINOPTION_YIQ_YVALUE); }
float screen_yiq_i() const { return float_value(WINOPTION_YIQ_IVALUE); }
float screen_yiq_q() const { return float_value(WINOPTION_YIQ_QVALUE); }