Sony Megatron Colour Video Monitor

First off, just to get it out of the way: the version of your decoupling with crt-guest-advanced-ntsc-pass1.slang included blows out/massively overbrightens the image in HDR on my system. Changing float_framebuffer8 to false (or changing srgb_framebuffer8 to true) appears to fix this at a glance, but i suppose there may be unintended consequences?

That said:

crt-guest-advanced-ntsc-pass1.slang calls LinearizePass, the previous shader in the chain (alias7 in your decoupling) in three places.

If those calls are replaced with NtscPass (alias4/custom-fast-sharpen.slang in your decoupling) the resulting preset loads, but doing that would obviously break crt-guest-advanced-ntsc.

Either continuing to use stocks for the dummy alias or adding a “crt-guest-advanced-ntsc-pass1a.slang” with those alias calls changed seem like the best solutions? What would you suggest hunterk?

The preset seems to load without issue with the stocks you have at shader5 and shader6 removed outright.

(ntsc-pass3.slang calls PrePass0/alias0 a couple times as well, but that is explicitly pulling a pre ntsc-pass1.slang version of the frame, so i think that just needs to be left alone barring more extensive changes to the shader scripting.)

2 Likes

Whoops, accidentally posted that as a reply to the thread rather than to you specifically.

1 Like

Yup sounds like a plan! This should be dead simple to add - the only problem is fitting it all into one line in the RA UI!

1 Like

Yeah Id guess the same, although a bit dirty I doubt it has too detrimental effect as these (I think!) boil down to copies of 320x240p textures at most as far as I remember. Great stuff Im going to give these a spin on some NES stuff.

1 Like

So are you saying you couldnt get it to load? If so thats odd as @GPDP1 has got screenshots so there must be some difference in what youre both doing. I want to give this a try when I find some time so hopefully it works in one of the ways above.

1 Like

If it’s too dirty or hacky, maybe you can just stick to the leaner, lighter version @GPDP1 isolated first, at least for now.

After spending more time tweaking, I doubt I even need the other filtering and sharpening stuff anymore. I would even argue that it’s a separate module from the NTSC stuff.

Just the Super-XBR stuff plus the 5 pass NTSC stuff should work wonders.

I’ve finished with my first release of my CyberLab Megatron Death To Pixels 4K HDR Preset Pack by the way! Just to upload and share it now. Will probably do a quick Mega share followed by GitHub later.

Here it is:

Click the link below to download

CyberLab Megatron Death To Pixels 4K HDR Shader Preset Pack

2 Likes

Oh, no, it loads fine. I was just helping @GPDP1 workshop cutting out the stock passes.

I think the blown out brightness in HDR thing is only a problem when the decoupled NTSC preset is loaded by itself without Megatron appended, due to the last shader in the chain (crt-guest-advanced-ntsc-pass1.slang) having float_framebuffer8 set to true in the version of the preset GPDP1 posted. My adaptive ntsc-adaptive presets display the same behavior if i change their final float_framebuffer from false to true.

2 Likes
shaders = "6"
shader0 = "shaders_slang/crt/shaders/guest/advanced/stock.slang"
filter_linear0 = "false"
wrap_mode0 = "clamp_to_border"
mipmap_input0 = "false"
alias0 = "PrePass0"
float_framebuffer0 = "false"
srgb_framebuffer0 = "false"
scale_type_x0 = "source"
scale_x0 = "1.000000"
scale_type_y0 = "source"
scale_y0 = "1.000000"
shader1 = "shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass1.slang"
filter_linear1 = "false"
wrap_mode1 = "clamp_to_border"
mipmap_input1 = "false"
alias1 = "NPass1"
float_framebuffer1 = "true"
srgb_framebuffer1 = "false"
scale_type_x1 = "source"
scale_x1 = "4.000000"
scale_type_y1 = "source"
scale_y1 = "1.000000"
shader2 = "shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass2.slang"
filter_linear2 = "true"
wrap_mode2 = "clamp_to_border"
mipmap_input2 = "false"
alias2 = ""
float_framebuffer2 = "true"
srgb_framebuffer2 = "false"
scale_type_x2 = "source"
scale_x2 = "0.500000"
scale_type_y2 = "source"
scale_y2 = "1.000000"
shader3 = "shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass3.slang"
filter_linear3 = "true"
wrap_mode3 = "clamp_to_border"
mipmap_input3 = "false"
alias3 = ""
float_framebuffer3 = "false"
srgb_framebuffer3 = "false"
scale_type_x3 = "source"
scale_x3 = "1.000000"
scale_type_y3 = "source"
scale_y3 = "1.000000"
shader4 = "shaders_slang/crt/shaders/guest/advanced/custom-fast-sharpen.slang"
filter_linear4 = "true"
wrap_mode4 = "clamp_to_border"
mipmap_input4 = "false"
alias4 = "NtscPass"
float_framebuffer4 = "false"
srgb_framebuffer4 = "false"
scale_type_x4 = "source"
scale_x4 = "1.000000"
scale_type_y4 = "source"
scale_y4 = "1.000000"
shader5 = "shaders_slang/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass1a.slang"
filter_linear5 = "true"
wrap_mode5 = "clamp_to_border"
mipmap_input5 = "false"
alias5 = "Pass1"
float_framebuffer5 = "false"
srgb_framebuffer5 = "false"
scale_type_x5 = "viewport"
scale_x5 = "1.000000"
scale_type_y5 = "source"
scale_y5 = "1.000000"

With “crt-guest-advanced-ntsc-pass1a.slang” being:

#version 450

/*
   CRT - Guest - NTSC - Pass1 (Decoupled)
   
   Copyright (C) 2018-2022 guest(r) - [email protected]

   Incorporates many good ideas and suggestions from Dr. Venom.
   I would also like give thanks to many Libretro forums members for continuous feedback, suggestions and caring about the shader.
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   
*/

layout(push_constant) uniform Push
{
	vec4 SourceSize;
	vec4 OriginalSize;
	vec4 OutputSize;
	uint FrameCount;
	float SIGMA_HOR;
	float HSHARPNESS;
	float S_SHARP;
	float HARNG;
	float HSHARP; 
	float spike;
	float internal_res;
} params;

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


#pragma parameter bogus_filtering "[ FILTERING OPTIONS ]: " 0.0 0.0 1.0 1.0

#pragma parameter HSHARPNESS "          Horizontal Filter Range" 1.5 1.0 8.0 0.05
#define HSHARPNESS params.HSHARPNESS

#pragma parameter SIGMA_HOR "          Horizontal Blur Sigma" 0.90 0.1 7.0 0.05
#define SIGMA_HOR params.SIGMA_HOR

#pragma parameter S_SHARP "          Substractive Sharpness" 0.9 0.0 2.0 0.10
#define S_SHARP params.S_SHARP

#pragma parameter HSHARP "          Sharpness Definition" 1.2 0.0 2.0 0.10
#define HSHARP params.HSHARP

#pragma parameter HARNG "          Substractive Sharpness Ringing" 0.4 0.0 4.0 0.10
#define HARNG params.HARNG 

#pragma parameter spike "          Scanline Spike Removal" 1.0 0.0 2.0 0.10
#define spike params.spike

#define COMPAT_TEXTURE(c,d) texture(c,d)
#define TEX0 vTexCoord

#define OutputSize params.OutputSize
#define gl_FragCoord (vTexCoord * OutputSize.xy)

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

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

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

float invsqrsigma = 1.0/(2.0*SIGMA_HOR*SIGMA_HOR);

float gaussian(float x)
{
	return exp(-x*x*invsqrsigma);
}

void main()
{	
	vec2 prescalex = vec2(textureSize(NtscPass, 0)) / params.OriginalSize.xy;

	vec4 SourceSize = params.OriginalSize * vec4(2.0*prescalex.x, prescalex.y, 0.5/prescalex.x, 1.0/prescalex.y);

	float f = fract(SourceSize.x * vTexCoord.x);
	f = 0.5 - f;
	vec2 tex = floor(SourceSize.xy * vTexCoord)*SourceSize.zw + 0.5*SourceSize.zw;
	vec3 color = 0.0.xxx;
	float scolor = 0.0;
	vec2 dx  = vec2(SourceSize.z, 0.0);

	float w = 0.0;
	float swsum = 0.0;
	float wsum = 0.0;
	vec3 pixel;

	float hsharpness = HSHARPNESS;
	vec3 cmax = 0.0.xxx;
	vec3 cmin = 1.0.xxx;
	float sharp = gaussian(hsharpness) * S_SHARP;
	float maxsharp = 0.20;
	float FPR = hsharpness;
	float fpx = 0.0;
	float sp = 0.0;
	float sw = 0.0;

	float ts = 0.025;
	vec3 luma = vec3(0.2126, 0.7152, 0.0722); 

	float LOOPSIZE = ceil(2.0*FPR);
	float CLAMPSIZE = round(2.0*LOOPSIZE/3.0);
	
	float n = -LOOPSIZE;
	
	do
	{
		pixel  = COMPAT_TEXTURE(NtscPass, tex + n*dx).rgb;
		sp = max(max(pixel.r,pixel.g),pixel.b);
		
		w = gaussian(n+f) - sharp;
		fpx = abs(n+f-sign(n)*FPR)/FPR;
		if (abs(n) <= CLAMPSIZE) { cmax = max(cmax, pixel); cmin = min(cmin, pixel); }
		if (w < 0.0) w = clamp(w, mix(-maxsharp, 0.0, pow(clamp(fpx,0.0,1.0), HSHARP)), 0.0);
	
		color = color + w * pixel;
		wsum  = wsum + w;

		sw = max(w, 0.0) * (dot(pixel,luma) + ts); 
		scolor = scolor + sw * sp;
		swsum = swsum + sw;
		
		n = n + 1.0;
			
	} while (n <= LOOPSIZE);

	color = color / wsum;
	scolor = scolor / swsum;
	
	color = clamp(mix(clamp(color, cmin, cmax), color, HARNG), 0.0, 1.0); 
	
	scolor = clamp(mix(max(max(color.r, color.g),color.b), scolor, spike), 0.0, 1.0);
	
	FragColor = vec4(color, scolor);
}

Note that, just like unmodified ntsc-adaptive, these presets fail to blend pseudo-hires dithering on Super Famicom titles like Kirby’s Dream Land 3. In those cases, scale_type_x1 = “source” needs to be changed to scale_type_x1 = “absolute”, and scale_x1 = “4.000000” needs to be changed to scale_x1 = “1024”.

2 Likes

Very nice! I was gonna try my hand at it today, but it seems like you saved me the trouble. Works very well, to be sure.

Are you sure about this? I was able to blend it just fine by using Mixed NTSC Phase, with resolution scaling set to 0.75:

Only problem is, at least with the SNES9X core, it gets mighty blurry when you go into a screen that uses the regular 256x224 resolution. I don’t know if that’s correct. I certainly don’t remember the game looking sharper or blurrier when entering certain screens back in the day. Perhaps there’s something to be said for having the game always output in 512x224 like the old bsnes-accuracy core would.

One other thing: might it be possible to remove the Remove Scanline Spike parameter? I don’t think it does anything here outside the context of guest’s original preset, and in fact I seem to remember it being placed elsewhere in guest’s other presets, but it’s placed in the filtering options here for some reason, so to clean it up just a bit further, it might make sense to get rid of it entirely for this preset.

2 Likes

So just created a pull request for V5.6 of the Sony Megatron.

The major addition is that of the phosphor set primaries that @Azurfel pointed out were missing. The reason why this change has seemingly leap frogged other changes is because it was dead simple to do and an important addition. The other change I made was with regards to @cyber comment about trying to do something about the fact HDR needs both peak and paper white luminance set. Essentially all I’ve managed to do is jiggle around the order of the settings so that they are first.

I was planning on adding rotation of the scanlines and masks but this requires a bit of work that I’ve not found time for yet BUT I will do it.

Thanks again for all the support!

3 Likes

@GPDP1 Just tried your above patch using @guest.r NTSC simulation and it is an incredible signal simulation - really well done Guest. I’m definitely thrown back to my 1980’s bedroom on my RF CRT. I need to play some Spectrum games now (of course the best computer ever made - what more could you want than a rubber keyboard built in - actually scratch that - its the best thing humanity has ever made - we peaked)

2 Likes

Here’s the PVM 1910 SDR Megatron preset modified to use the 600 TVL mask (for more brightness) and 6500K color temperature (personal preference), combined with the NTSC preset modified to minimize artifacts and maximize sharpness while still fully blending the pseudo-hires dithering:

2 Likes

I can’t reproduce any problems with transparency on kirby’s dreamland 3 using snes9x or bsnes with the ntsc-adaptive that’s in the repo.

2 Likes

This is what i get with freshly updated shaders regardless of core:

ntsc-adaptive

scale_type_x0 = "absolute"
scale_x0 = "1024"

Turns out i was using outdated shaders tho, so a more current version of crt-guest-advanced-ntsc-pass1a.slang:

#version 450

/*
   CRT - Guest - NTSC - Pass1 (Decoupled)
   
   Copyright (C) 2018-2023 guest(r) - [email protected]

   Incorporates many good ideas and suggestions from Dr. Venom.
   I would also like give thanks to many Libretro forums members for continuous feedback, suggestions and caring about the shader.
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   
*/

layout(push_constant) uniform Push
{
	vec4 SourceSize;
	vec4 OriginalSize;
	vec4 OutputSize;
	uint FrameCount;
	float SIGMA_HOR;
	float HSHARPNESS;
	float S_SHARP;
	float HARNG;
	float HSHARP; 
	float spike;
	float internal_res;
	float MAXS;
} params;

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


#pragma parameter bogus_filtering "[ FILTERING OPTIONS ]: " 0.0 0.0 1.0 1.0

#pragma parameter HSHARPNESS "          Horizontal Filter Range" 1.5 1.0 8.0 0.05
#define HSHARPNESS params.HSHARPNESS

#pragma parameter SIGMA_HOR "          Horizontal Blur Sigma" 0.90 0.1 7.0 0.05
#define SIGMA_HOR params.SIGMA_HOR

#pragma parameter S_SHARP "          Substractive Sharpness" 0.9 0.0 2.0 0.10
#define S_SHARP params.S_SHARP

#pragma parameter HSHARP "          Sharpness Definition" 1.2 0.0 2.0 0.10
#define HSHARP params.HSHARP

#pragma parameter MAXS "          Maximum Sharpness" 0.15 0.0 0.30 0.01
#define MAXS params.MAXS 

#pragma parameter HARNG "          Substractive Sharpness Ringing" 0.4 0.0 4.0 0.10
#define HARNG params.HARNG 

#pragma parameter spike "          Scanline Spike Removal" 1.0 0.0 2.0 0.10
#define spike params.spike

#define COMPAT_TEXTURE(c,d) texture(c,d)
#define TEX0 vTexCoord

#define OutputSize params.OutputSize
#define gl_FragCoord (vTexCoord * OutputSize.xy)

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

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

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

float invsqrsigma = 1.0/(2.0*SIGMA_HOR*SIGMA_HOR);

float gaussian(float x)
{
	return exp(-x*x*invsqrsigma);
}

void main()
{	
	vec2 prescalex = vec2(textureSize(NtscPass, 0)) / params.OriginalSize.xy;

	vec4 SourceSize = params.OriginalSize * vec4(2.0*prescalex.x, prescalex.y, 0.5/prescalex.x, 1.0/prescalex.y);

	float f = fract(SourceSize.x * vTexCoord.x);
	f = 0.5 - f;
	vec2 tex = floor(SourceSize.xy * vTexCoord)*SourceSize.zw + 0.5*SourceSize.zw;
	vec3 color = 0.0.xxx;
	float scolor = 0.0;
	vec2 dx  = vec2(SourceSize.z, 0.0);

	float w = 0.0;
	float swsum = 0.0;
	float wsum = 0.0;
	vec3 pixel;

	float hsharpness = HSHARPNESS;
	vec3 cmax = 0.0.xxx;
	vec3 cmin = 1.0.xxx;
	float sharp = gaussian(hsharpness) * S_SHARP;
	float maxsharp = MAXS;
	float FPR = hsharpness;
	float fpx = 0.0;
	float sp = 0.0;
	float sw = 0.0;

	float ts = 0.025;
	vec3 luma = vec3(0.2126, 0.7152, 0.0722); 

	float LOOPSIZE = ceil(2.0*FPR);
	float CLAMPSIZE = round(2.0*LOOPSIZE/3.0);
	
	float n = -LOOPSIZE;
	
	do
	{
		pixel  = COMPAT_TEXTURE(NtscPass, tex + n*dx).rgb;
		sp = max(max(pixel.r,pixel.g),pixel.b);
		
		w = gaussian(n+f) - sharp;
		fpx = abs(n+f-sign(n)*FPR)/FPR;
		if (abs(n) <= CLAMPSIZE) { cmax = max(cmax, pixel); cmin = min(cmin, pixel); }
		if (w < 0.0) w = clamp(w, mix(-maxsharp, 0.0, pow(clamp(fpx,0.0,1.0), HSHARP)), 0.0);
	
		color = color + w * pixel;
		wsum  = wsum + w;

		sw = max(w, 0.0) * (dot(pixel,luma) + ts); 
		scolor = scolor + sw * sp;
		swsum = swsum + sw;
		
		n = n + 1.0;
			
	} while (n <= LOOPSIZE);

	color = color / wsum;
	scolor = scolor / swsum;
	
	color = clamp(mix(clamp(color, cmin, cmax), color, HARNG), 0.0, 1.0); 
	
	scolor = clamp(mix(max(max(color.r, color.g),color.b), scolor, spike), 0.0, 1.0);
	
	FragColor = vec4(color, scolor);
}

or with scanline spike commented out as @GPDP1 suggested

#version 450

/*
   CRT - Guest - NTSC - Pass1 (Decoupled)
   
   Copyright (C) 2018-2023 guest(r) - [email protected]

   Incorporates many good ideas and suggestions from Dr. Venom.
   I would also like give thanks to many Libretro forums members for continuous feedback, suggestions and caring about the shader.
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   
*/

layout(push_constant) uniform Push
{
	vec4 SourceSize;
	vec4 OriginalSize;
	vec4 OutputSize;
	uint FrameCount;
	float SIGMA_HOR;
	float HSHARPNESS;
	float S_SHARP;
	float HARNG;
	float HSHARP; 
// 	float spike;
	float internal_res;
	float MAXS;
} params;

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


#pragma parameter bogus_filtering "[ FILTERING OPTIONS ]: " 0.0 0.0 1.0 1.0

#pragma parameter HSHARPNESS "          Horizontal Filter Range" 1.5 1.0 8.0 0.05
#define HSHARPNESS params.HSHARPNESS

#pragma parameter SIGMA_HOR "          Horizontal Blur Sigma" 0.90 0.1 7.0 0.05
#define SIGMA_HOR params.SIGMA_HOR

#pragma parameter S_SHARP "          Substractive Sharpness" 0.9 0.0 2.0 0.10
#define S_SHARP params.S_SHARP

#pragma parameter HSHARP "          Sharpness Definition" 1.2 0.0 2.0 0.10
#define HSHARP params.HSHARP

#pragma parameter MAXS "          Maximum Sharpness" 0.15 0.0 0.30 0.01
#define MAXS params.MAXS 

#pragma parameter HARNG "          Substractive Sharpness Ringing" 0.4 0.0 4.0 0.10
#define HARNG params.HARNG 

// #pragma parameter spike "          Scanline Spike Removal" 1.0 0.0 2.0 0.10
// #define spike params.spike

#define COMPAT_TEXTURE(c,d) texture(c,d)
#define TEX0 vTexCoord

#define OutputSize params.OutputSize
#define gl_FragCoord (vTexCoord * OutputSize.xy)

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

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

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

float invsqrsigma = 1.0/(2.0*SIGMA_HOR*SIGMA_HOR);

float gaussian(float x)
{
	return exp(-x*x*invsqrsigma);
}

void main()
{	
	vec2 prescalex = vec2(textureSize(NtscPass, 0)) / params.OriginalSize.xy;

	vec4 SourceSize = params.OriginalSize * vec4(2.0*prescalex.x, prescalex.y, 0.5/prescalex.x, 1.0/prescalex.y);

	float f = fract(SourceSize.x * vTexCoord.x);
	f = 0.5 - f;
	vec2 tex = floor(SourceSize.xy * vTexCoord)*SourceSize.zw + 0.5*SourceSize.zw;
	vec3 color = 0.0.xxx;
	float scolor = 0.0;
	vec2 dx  = vec2(SourceSize.z, 0.0);

	float w = 0.0;
	float swsum = 0.0;
	float wsum = 0.0;
	vec3 pixel;

	float hsharpness = HSHARPNESS;
	vec3 cmax = 0.0.xxx;
	vec3 cmin = 1.0.xxx;
	float sharp = gaussian(hsharpness) * S_SHARP;
	float maxsharp = MAXS;
	float FPR = hsharpness;
	float fpx = 0.0;
	float sp = 0.0;
	float sw = 0.0;

	float ts = 0.025;
	vec3 luma = vec3(0.2126, 0.7152, 0.0722); 

	float LOOPSIZE = ceil(2.0*FPR);
	float CLAMPSIZE = round(2.0*LOOPSIZE/3.0);
	
	float n = -LOOPSIZE;
	
	do
	{
		pixel  = COMPAT_TEXTURE(NtscPass, tex + n*dx).rgb;
		sp = max(max(pixel.r,pixel.g),pixel.b);
		
		w = gaussian(n+f) - sharp;
		fpx = abs(n+f-sign(n)*FPR)/FPR;
		if (abs(n) <= CLAMPSIZE) { cmax = max(cmax, pixel); cmin = min(cmin, pixel); }
		if (w < 0.0) w = clamp(w, mix(-maxsharp, 0.0, pow(clamp(fpx,0.0,1.0), HSHARP)), 0.0);
	
		color = color + w * pixel;
		wsum  = wsum + w;

		sw = max(w, 0.0) * (dot(pixel,luma) + ts); 
		scolor = scolor + sw * sp;
		swsum = swsum + sw;
		
		n = n + 1.0;
			
	} while (n <= LOOPSIZE);

	color = color / wsum;
	scolor = scolor / swsum;
	
	color = clamp(mix(clamp(color, cmin, cmax), color, HARNG), 0.0, 1.0); 
	
// 	scolor = clamp(mix(max(max(color.r, color.g),color.b), scolor, spike), 0.0, 1.0);
	
	FragColor = vec4(color, scolor);
}
2 Likes

This is par for the course when dropping the NTSC Scale so low for the purposes of perfect pseudo transparency blending.

First try increasing the Chroma/Blending Scale. After that the simple but effective solution to this is to adjust one or more of the sharpness settings until things become legible again.

Amazingly, the transparency effects should remain intact.

As a matter of fact I wouldn’t be surprised if CRT’s used analog circuitry to sharpen up the signal. I remember adjusting a screw on some old AOC monitors to do just that and many sets had sharpness controls.

I think Toshiba sets had some sharpening circuitry as well.

Try it and see.

1 Like

Oh, believe me, I do all of those things (see my last pic). Again, though, the issue is the screens that use pseudo-hires for transparency effects look just fine, but the ones that don’t look a lot blurrier, since they’re running at a lower horizontal resolution. Again, unless someone with access to real hardware and a CRT can confirm otherwise, I don’t think this is what’s supposed to happen.

2 Likes

Well this is something that I have noticed as well. It’s very easy to see this in Turbo Duo (PC-Engine) games. 2 Phase at the same Resolution Scale settings is always blurrier than 3 phase. So with multi-res games you end up with the phase switching but you have to use the tuning for whichever phase type you had set when you did your tuning.

This is something I was going to bring up at some point because I’ve heard people saying that PC-Engine uses 2 Phase NTSC but with the NTSC Adaptive algorithm this system uses 2 and 3 phase NTSC in many games.

I think the solution to this would be to have independent Resolution Scale (and Chroma/Blending Scale) controls for each phase type. What do you think about this @guest.r, @hunterk et al?

In the interim you can just use the discrete Phase settings. So for Turbo Duo (PCE) Phase Type 2, Merge Fields 1. For SNES and NES Phase Type 3, Merge Fields 1. For Sega Genesis, Phase Type 2, Merge Fields 0.

1 Like

AFAIK, which phase to use is entirely dependent on the resolution, which is why ntsc-adaptive exists. That is, for cores/games that change resolution mid-game, so you would have to keep swapping between 3-phase and 2-phase presets any time it changes.

2 Likes

Fair enough but does this resolution dependent algorithm mimic the behaviour of actual consoles or was it just a convenient but rudimentary solution to the problem of how to be able to have just one NTSC Shader/Preset to be able to work for different Phase Types instead of requiring 2 separate shaders?

The current behaviour leaves a little to be desired due to the huge change in blur at the same Resolution Scale settings (because there is only a single, united Resolution Scale setting for both phase types).

Having 2 sets of Resolution Scale and Chroma/Blending Scale controls would allow us to address this inconsistency so we can set whatever Resolution Scale we want for 2 Phase and we can set whatever Resolution Scale we want for 3 Phase so that if the phase changes mid game the level of blur between the different phases would be whatever we desire.

Even if the current behaviour is the most accurate compared to real hardware, it shouldn’t hurt to give users a bit more leeway to fine tune things however they desire.

The alternative to this is that the weighting or the offset could be adjusted internally (or manually) in the final resolution scale used so that if the Resolution Scale is set to 1 for example, if a user (or the Auto algorithm) switches between both Phase types mid game, the effective resolution and level of blur as well as the Chroma/Blending Scale will be consistent for both Phase Types.

Currently, a Resolution Scale settings of 1.0 blends basically almost all types of dither patterns across Sega Genesis, Turbo Duo and possibly many other consoles’ games once the Phase Type is set to 2 Phase Mode. However, this doesn’t blend SNES pseudo transparency in HiRes mode using 3 Phase Mode. Instead an NTSC Scale of 0.75 needs to be used to achieve the same level of blending as 1.0 in 2 Phase Mode.

This creates the problem in multi-res games which would trigger a Phase Type change as resolution changes because we only have a single NTSC Scale setting to govern both 2 Phase and 3 Phase and we just lowered it to 0.75.

0.75 might still leave things sharp and in focus enough for HiRes mode to remain comfortably playable but when the Resolution changes and things switch to low res mode and 2 Phase, that 0.75 setting might make things a bit inconsistent, blurry and somewhat jarring.

I’m unaware of ever noticing this type of behaviour on real hardware. My suggestions above are all aimed at addressing this.

1 Like

Oh wow - sorry I missed this earlier. Ill have to give your release a whirl. Sounds great!

1 Like