Welcome, Guest.
Username: Password: Remember me

TOPIC: Apply shader every x frames

Apply shader every x frames 11 months 3 weeks ago #1

Hello

Is it possible to apply a shader every x frames instead of every frame?

I have tried declaring a "counter" variable, incrementing it, and then using the modf function % (modulo) to check if the remainder when divided by 2 equals 0, in order to apply the shader only every second frame, but nothing I try works (syntax/unexpected errors). Any guidance would be appreciated. I have basic knowledge of global/static scope, and from what I gather I should "return tex2D(RFX_backbufferColor, texcoord);" in order to make no modification to the final output colour. I would like to save as much GPU usage as possible for frames that don't receive any modification, so ideally I would not even want to perform any technique/pass on those alternate frames (if possible).

Thanks

edit: it looks like I should probably use
uniform float frametime < source = "frametime"; >;
Time in milliseconds it took for the last frame to complete.
uniform int framecount < source = "framecount"; >;
Total amount of frames since the game started.

edit: seems framecount doesn't work (or is unreliable), but timer seems to be ok
uniform float timer < source = "timer"; >;
Last Edit: 11 months 3 weeks ago by pneumatic.
The administrator has disabled public write access.

Apply shader every x frames 11 months 3 weeks ago #2

Framecount should work just fine, but keep in mind it may contain very big numbers that do not work well in floating point precision, so you should modulo on the integer value directly.
Also, to avoid confusion in the future: It is not possible to write to global variables in a shader. Uniforms (all global variables are implicitly uniform even if you omit the keyword) are strictly read-only. The only way to write data from a shader is through color output to a texture.
Cheers, crosire =)
The administrator has disabled public write access.
The following user(s) said Thank You: pneumatic

Apply shader every x frames 11 months 3 weeks ago #3

crosire wrote:
Framecount should work just fine

Actually I just realised framecount is not right for my application, because the duration between x number of frames will vary depending on how many fps the GPU is currently rendering. What I want to do is "apply this shader only if it hasn't been applied in x milliseconds" , which the timer variable would be good for (i.e check if it has increased by x ms since last pass) but like you say "not possible to write to global variables" which seems to be a requirement for such a thing (I tried static ones inside the pass function, to keep track of what the previous timer value was; doesn't seem to work). Hmmm.
Last Edit: 11 months 3 weeks ago by pneumatic.
The administrator has disabled public write access.

Apply shader every x frames 11 months 3 weeks ago #4

Well, I can't get framecount to work either. What am I doing wrong?
NAMESPACE_ENTER(CFX)

#include CFX_SETTINGS_DEF

#if (USE_CUSTOM == 1)
uniform int framecount < source = "framecount"; >;

float4 PS_Custom(float4 vpos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
{
	if ((framecount % 60) == 0)
	{
		//the shader here should only execute once every 60 frames
		//but it keeps getting executed every frame
	}
		
	else
		return tex2D(RFX_backbufferColor, texcoord);
}

technique Custom_Tech <bool enabled = RFX_Start_Enabled; int toggle = Custom_ToggleKey; >
{
	pass CustomPass
	{
		VertexShader = RFX_VS_PostProcess;
		PixelShader = PS_Custom;
	}
}

#endif

#include CFX_SETTINGS_UNDEF

NAMESPACE_LEAVE()
The administrator has disabled public write access.

Apply shader every x frames 11 months 3 weeks ago #5

If you are trying to use the code in a D3D9 application, note that D3D9 has no integer operations in shader code, so ReShade emulates them using floating point operations. This means you will run into precision errors and as such should do something like this:
#include "Reshade.fxh"

uniform int framecount < source = "framecount"; >;

float3 Main(in float4 position : SV_Position, in float2 texcoord : TEXCOORD0) : SV_Target
{
	// instead of "== 0", since the floating point operation may not result in an exact zero
	if ((framecount % 60) < 0.01f)
	{
		return float3(0, 1, 0);
	}
	else
	{
		return tex2D(ReShade::BackBuffer, texcoord).rgb;
	}
}

technique Test
{
	pass
	{
		VertexShader = PostProcessVS;
		PixelShader = Main;
	}
}
I verified that this works.
Cheers, crosire =)
Last Edit: 11 months 3 weeks ago by crosire.
The administrator has disabled public write access.

Apply shader every x frames 11 months 3 weeks ago #6

Thanks, that works :)

I'm now trying to apply the following rule to the remaining frames: "render whatever the previous frame of this shader was".

In effect what I'm trying to do is put a frame rate limiter onto the shader itself.
I have followed your example here , however I get "error X3503: '___main': function return value missing semantics".

Here is my code
NAMESPACE_ENTER(CFX)
#include CFX_SETTINGS_DEF

#if (USE_CUSTOM == 1)
uniform float framecount < source = "framecount"; >;
texture2D currTex : COLOR;
texture2D prevTex { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; };
sampler2D currColor { Texture = currTex; };
sampler2D prevColor { Texture = prevTex; };


float4 PS_Custom(float4 position : SV_Position, float2 texcoord : TEXCOORD, out float4 color : SV_Target0, out float4 prevOut : SV_Target1) 
{
	
	color = tex2D(currColor, texcoord);
	float4 prev = tex2D(prevColor, texcoord);
	prevOut = color;
	
	
	if ((framecount % 3) < 0.01f)
	{
		//1 in 3 frames receives this shader code
		
	}
	
	else
		return prev;  //else, whatever the previous frame was
	

}

technique Custom_Tech <bool enabled = RFX_Start_Enabled; int toggle = Custom_ToggleKey; >
{
	pass CustomPass
	{
		VertexShader = RFX_VS_PostProcess;
		PixelShader = PS_Custom;
                RenderTarget1 = prevTex;
	}
}


#endif
#include CFX_SETTINGS_UNDEF
NAMESPACE_LEAVE()

btw I am testing in DX9 with ReShade v2.
Last Edit: 11 months 3 weeks ago by pneumatic.
The administrator has disabled public write access.

Apply shader every x frames 11 months 3 weeks ago #7

You declared a function with 2 out parameters and one return type. The return type has no semantic on it, so ReShade doesn't know what to do with it (which rendertarget the result is supposed to be written to).
float4 /* <- return type */ PS_Custom(
    float4 position : SV_Position,
    float2 texcoord : TEXCOORD,
    out float4 color /* <- out parameter 1 */: SV_Target0 /* <- semantic for out parameter 1, result is written to render target at index 0 */,
    out float4 prevOut /* <- out paramter 2 */: SV_Target1 /* <- semantic for out parameter 2, result is written to render target at index 1*/
) /* <- missing semantic for return type */ { ... }
Your return type makes no sense if you already declared the "color" parameter as being an out parameter that writes to the first render target. Either get rid of the "color" parameter and declare the return type with "SV_Target0" semantic or get rid of the return type (make the function a "void") and write to the "color" parameter instead of returning a value inside the function.

Oh and don't use ReShade 2.
Cheers, crosire =)
Last Edit: 11 months 3 weeks ago by crosire.
The administrator has disabled public write access.
The following user(s) said Thank You: pneumatic