Shaders for Vulkan (new .slang shaders)

Basically I’m looking for “oldtv”. I want to convert this shader chain into slang. Pretty much every shader from there is already converted to slang except the “oldtv”.

Here is the original post of that shader chain by Birm.

I think i can help a bit porting the xBR shaders to .slang, since it’s very similar to GLSL. Unfortunately my card has no Vulkan support, but i can try help with a hand ported working GLSL version. It’s a copy/paste for functions and below texture lookups, but there is still much to do like calculating coordinates and reading the pixels + implementing the parameters. I hope it’s clear of bugs and that the transplantation will work. :slight_smile:

PS: it’s for Pete’s plugin, since i’ve done most of my ports there, but it shouldn’t matter too much.

Best regards, guest.r

Guest, thank you very much! I can do any necessary slang cleanups here. Between the two of us, I think we can get it. :slight_smile:

I just want to mention that i tinkered around with the accuracy feature and discovered that it adds two types of improvements. The first improvement is the removal of the jagged artifacts, the second is conceptual and affects general shaping. The second takes more precision metrics ops, but the first can be very lightweight and makes the shader better. My port includes the jagged artifacts patch and i wanted to share the results with you guys, who are doing excellent job btw. I’m a great fan. :slight_smile:

currently working on translating scalefx to slang. I’m really missing the vector functionality of operators. ok, so (x <= y) can be replaced by lessThanEqual(x,y) and (a ? b : c) by using mix(c,b,a). but what about logical operators on vectors? in cg I could combine two bool4 vectors a,b like this a || b, which would do component-wise or operations. I haven’t found an equivalent function for that in GLSL. I guess you have to write it down for every component seperately? this would make an already complex code very convoluted. hope there is another solution.

edit: well I found one way to do it, maybe there is a more elegant one. here is the function in cg:

bool clear(float2 crn, float4 ort){
	return all(crn.xyxy <= THR || crn.xyxy <= ort || crn.xyxy <= ort.wxyz);
}

and in slang:

bool clear(vec2 crn, vec4 ort){
	return all(bvec4(step(crn.xyxy, vec4(THR)) + step(crn.xyxy, ort) + step(crn.xyxy, ort.wxyz)));
}

where I used that you can calculate x <= y with step(x,y).

maybe I should get rid of boolean values altogether and just operate with numerical values:

float clear(vec2 crn, vec4 ort){
	vec4 res = step(crn.xyxy, vec4(THR)) + step(crn.xyxy, ort) + step(crn.xyxy, ort.wxyz);
	return min(res.x * res.y * res.z * res.w, 1);
}

any thoughts?

Is there a speed benefit to replacing the bools with numerical values? I know the min will still branch, but I would think the numerical comparisons would be faster.

Storing the boolean state as a float also seems useful insofar as you can do things like (a > b) to say “if a is true and b is false”, which GLSL doesn’t allow natively (AFAIK; that is, you can’t normally substitute 0 for false and 1 for true the way you can in Cg).

using numerical values I have to use a few mins here and there to avoid invalid values. I don’t think it’s that big of a deal but is there any other way to clamp them without introducing branches?

Well, internets suggest that min/max/clamp really aren’t as bad as a legit if/then branch: https://www.opengl.org/discussion_boards/showthread.php/167935-GLSL-Branching-and-Clamp-function because they’re built-in/optimized, so i think you’re doing the best you can.

uh, just noticed that the ternary operator ?: is actually supported. okay, must’ve done something wrong. well this makes the process a whole lot easier. replacing it with mix would’ve been an unreadable mess.

shader parameters still don’t work for slang, right?

In my experience, they do sometimes, like right after I’ve loaded the shader preset. If I modify the shader stack though, they seem to disappear.

That’s weird. I haven’t had any problems with them not showing up as long as the shader is compiled successfully.

how do you properly implement them then? this line here:

#pragma parameter SFX_CLR "ScaleFX Color Thresh" 0.35 0.0 1.00 0.01

gives me the following error the first instance I try to use this variable in the code:

ERROR: scalefx-pass1.slang:53: 'SFX_CLR' : undeclared identifier

I just haven’t noticed it so far since I used the old fallback code:

#ifdef PARAMETER_UNIFORM
	uniform float SFX_CLR;
#else
	#define SFX_CLR   0.35
#endif

it seems though that it actually goes into the else case. the shader parameter shows up in retroarch but altering has no actual effect. outcommenting the fallback code and I’m back to the error message above.

tested it with the windows x86_64 nightly build from today. here is the shader file in question: https://mega.nz/#!qZJ0jagS!TI-ibt3lXCd4WIb8DZTYGue530KETxUacw4Iq9mkDz8

Ah, yeah, it’s a little different in slang. The #ifdef stuff doesn’t apply to them at all. Here’s a fairly simple example of how it should look:

Basically, add the floats to the push uniform struct thing*, add the #pragma lines anywhere (I like to put them right below the push struct) and then reference them later with struct_name.parameter_name. If you don’t feel like writing struct_name.* a bunch of times, you can also just #define it once for each variable, like I’ve done here:

That shader also has a bunch of Cg/HLSL > GLSL compatibility boilerplate #defines that can make porting a little more forgiving (particularly if you’re testing with an Nvidia GPU, which doesn’t care as much about Cg/HLSL-isms showing up in GLSL but will choke on Intel/AMD). I used them to port some of Hyllian’s simpler shaders with few additional changes.

*The push variables are apparently faster than the global variables, particularly for variables used in the fragment stage, but you only get 27 push slots (i.e., a vec4 takes up 4 slots, a float takes up 1, etc.) and the mat4 MVP only works in global. You can name the push struct thing whatever you want; maister usually calls his ‘register’, r5 and I call ours ‘params’, since that’s what we put there.

thanks for the help hunterk, I’ll try that.

is there a way to translate relative shader references to slang? when using multipass shader in combination with others, PassOutput# leads to errors because of the now different unforseen pass numbering. I’ve read you can access passes by name, any example for that? in my case when using scalefx twice in a row, this would cause the issue though with different passes having the same name.

You can look at crt-lottes-multipass.slangp, which uses aliases pretty extensively in the culminating shader pass’s fragment stage.

Unfortunately, I don’t think there’s any good way to do the double thing. Best solution, I think, is to just have a duplicate pass that references the different aliases. It’s massive code duplication, which sucks, but I guess you could use some #includes to reduce that.

Hey duddy, I hope you are doing good. Any luck with porting MudLord’s “oldtv” shader to Vulkan?

I just tried and it has some weird stuff going on that’s messing with the vignetting and screen curvature. Mudlord would have to port it himself.