Welcome, Guest.
Username: Password: Remember me

TOPIC: Issues with flow control... please help...

Issues with flow control... please help... 11 months 3 weeks ago #1

I'm trying to modify ReShade so that it will automatically and dynamically turn off certain shaders (those with high performance cost) if the frame rate is below a certain FPS threshold, based on frametime (RFX_FrameTime).

The basic idea here is, if the previous frame rendered slowly, then assume a low FPS, and switch off high-cost shaders.

I have been trying to do this by adding in a conditional segment at the top of the Util.h files as follows (using Ambient Light as an example)...
#if (RFX_FrameTime > 33.33333)
     #undef USE_AMBIENT_LIGHT
     #define USE_AMBIENT_LIGHT 0
#endif

But when I do it this way, I get a compile error telling me that it is an illegal #if statement.

I've tried changing it to use real if statements like so...
if (RFX_FrameTime > 33.33333)
{
     #undef USE_AMBIENT_LIGHT
     #define USE_AMBIENT_LIGHT 0
}

But that gives me a syntax error saying it is an unexpected if.

So clearly, I'm failing to understand where/when #if and if statements are allowed and functional (either that or my code editor is screwing things up, even though everything looks right).


If it comes down to it, I could modify the call checks for each shader individually, and modify the existing #if statements...

from
#if (AL_Adaptation && USE_AMBIENT_LIGHT) || USE_AL_DETECTLOW
to
#if ((AL_Adaptation && USE_AMBIENT_LIGHT) || USE_AL_DETECTLOW) && (RFX_FraameTime < 33.33333)

But I was hoping for something that could be more readily adjusted by having large blocks instead of multiple single lines changed.


I'd really appreciate some insight and help with why my #if and regular if statements are considered invalid by the compiler. I'd also appreciate it if someone could give some suggestions on how I might be able to actually accomplish this with blocks of code in just a few files, instead of having to adjust multiple lines across a large number of files.

Thanks,
Drake
The administrator has disabled public write access.

Issues with flow control... please help... 11 months 3 weeks ago #2

OK, I think I figured it out (now that I've read all of the Remarks section here). The #if statement cannot handle float numbers for the expression. Since I'm using float numbers, it's flagging as illegal. So I need to modify the way I make the check.

I'll try to think of a way to handle that, then try it out. I'll post back here again with the results (especially if I get it working), in case anyone else is interested at some point.

Later,
Drake
Last Edit: 11 months 3 weeks ago by DrakePhoenix.
The administrator has disabled public write access.

Issues with flow control... please help... 11 months 3 weeks ago #3

OK, got it to successfully compile...

In the ReShade.fx file, added in the following code just above the "Effects" section:
int Adaptive_Toggles(out int toggleOff)
{
     toggleOff = 0;
     float MinFPSThreshold = 30.0f; // Define the minimum desired FPS frame rate.  If frame rate falls below this value, then high performance cost shaders will be disabled for the current frame processing.  I've listed at 30.0f, but this could be set to a higher or lower value as desired.  But this currently has to be manually edited here in this file.
     float ToggleThreshold = (1000.0f / MinFPSThreshold); // Determines the frametime threshold to be ckecked against RFX_FrameTime.  1000ms divided by minimum FPS threshold = max frametime per frame.
     if (RFX_FrameTime > ToggleThreshold)
     {
          toggleOff = 1;
     }
     else
     {
          toggleOff = 0;
     }
     return toggleOff;
}

Then in each Util.h file that handles a shader I want to adapt in this way, as well as the Shared.h file for SweetFX, I added the following (giving the Adaptive Sharpen shader as an example this time, but many/any shaders can be added to the toggle section as needed, simply follow the same syntax pattern):
#if (Adaptive_Toggles == 1)
     #undef USE_ADAPTIVESHARPEN
     // other shaders undefined here
     #define USE_ADAPTIVESHARPEN 0
     // other shaders redefined to 0 here
#endif


While this compiles successfully, I have not yet tested if it functions properly or not. At some point in the next couple of days I'll set this up to toggle an effect that is clearly and definitely a major appearance change, such as a tonemapping or something, and play a game with settings that I know will have me hovering around the threshold point so that I can hopefully see it switching back and forth periodically as my FPS changes.

Later,
Drake
The administrator has disabled public write access.

Issues with flow control... please help... 11 months 3 weeks ago #4

  • crosire
  • crosire's Avatar
  • Offline
  • Posts: 2438
  • Thank you received: 1387
It won't work =). Preprocessor statements (beginning with "#") are simple text replacement macros and resolved before the compiler kicks in, a shader does not have any effect on them since they don't exist for them.

Example:
Source Code:
#define Test 1
void MyFunc1(float x) { }
void MyFunc2() { MyFunc1(Test); }
After the preprocessor finished:
void MyFunc1(float x) { }
void MyFunc2() { MyFunc1(1); }
Now the ReShade FX compiler starts and compiles this into HLSL/GLSL code. As you see, all preprocessor statements were resolved and are gone.

Turning off effects based on the framerate thus cannot be done via the preprocessor, it only runs during compilation. This has to be done in the actual shader code, which is executed every frame. Something like the following at the top of the shader code you want to disable if the framerate is too low should work: You cannot prevent a technique from running, but you can at least prevent it from doing heavy calculations by exiting early and simply returning the current contents of the backbufer:
const float MinFPSThreshold = 30.0f;
const float ToggleThreshold = (1000.0f / MinFPSThreshold);
if (RFX_FrameTime > ToggleThreshold)
{
    return tex2D(RFX_backbufferColor, texcoord);
}

I hope this helps.
Cheers, crosire =)
Last Edit: 11 months 3 weeks ago by crosire.
The administrator has disabled public write access.

Issues with flow control... please help... 11 months 3 weeks ago #5

OK, I think I see what you're saying.

Basically, because the Adaptive_Toggles function I designed runs as a full process, not preprocess, it isn't available to the preprocessor for the #if check I'm making. So I will have to set up the code specific to each individual shader.

But I'm not sure your code would work too well either, because most of the shaders look to me as though they define techniques as the void type, which won't allow a return (or is it that they only won't allow a return with a value, but will allow a valueless return?). Also, I don't understand why I can't prevent a technique from running. Can't we use the "enabled" and "toggle" aspects of a technique definition to specify a disabled technique based on variables?

Or, to show that in an example (let's take Adaptive Sharpen as an example)...

Keep my int Adaptive_Toggles(out int toggleOff) function in place in ReShade.fx. Then, in the shader file itself (AdaptiveSharpen.h in this example), add the following like so:

From
technique AdaptiveSharpen_Tech <bool enabled = RFX_Start_Enabled; int toggle = AdaptiveSharpen_ToggleKey; >
{
	pass AdaptiveSharpenPass1
To
bool techEnabled = RFX_Start_Enabled;
if (Adaptive_Toggles == 1)
{
     techEnabled = 0;
}
int disableToggle = Adaptive_Toggles;
int toggleEnabled = 0;
if (diableToggle == 0)
{
     toggleEnabled = AdaptiveSharpen_ToggleKey;
}
technique AdaptiveSharpen_Tech <bool enabled = techEnabled; int toggle = toggleEnabled; >
{
	pass AdaptiveSharpenPass1

That is all full code statements, right? So basically, it would prevent the technique running, by making it think it is disabled and untoggled, right?

But that raises a couple of questions for me: can regular if statements be used outside of a function like that, or would that result in the "unexpected if" error? In other words, would I have to make separate functions for it, and call the functions in place of techEnabled and toggleEnabled? Also, if the value of toggle is 0 instead of a normal key ID number, would it properly act to prevent toggle? And lastly (since my brain doesn't feel like it's working right and I can't remember how this works), would the code I added to ReShade.fx have to actually be added to each shader file instead, or would it be accessible to the shaders through the chain of #include statements (i.e. ReShade.fx includes Pipeline.cfg, which includes the shaders)?

If that wouldn't work (my example above, with or without moving the code from ReShade.fx to the shader files), could we simply make it so that the pass calls are nested inside of an if check, so that they only process if the if conditional is met, and otherwise the technique is effectively empty and does nothing? Example...

From
technique AdaptiveSharpen_Tech <bool enabled = RFX_Start_Enabled; int toggle = AdaptiveSharpen_ToggleKey; >
{
	pass AdaptiveSharpenPass1
	{
		VertexShader = RFX_VS_PostProcess;
		PixelShader = AdaptiveSharpenP0;
		RenderTarget = edgeTex;
	}
	
	pass AdaptiveSharpenPass2
	{
		VertexShader = RFX_VS_PostProcess;
		PixelShader = AdaptiveSharpenP1;
	}
}
To
technique AdaptiveSharpen_Tech <bool enabled = RFX_Start_Enabled; int toggle = AdaptiveSharpen_ToggleKey; >
{
	if (Adaptive_Toggles != 1)
	{
		pass AdaptiveSharpenPass1
		{
			VertexShader = RFX_VS_PostProcess;
			PixelShader = AdaptiveSharpenP0;
			RenderTarget = edgeTex;
		}
	
		pass AdaptiveSharpenPass2
		{
			VertexShader = RFX_VS_PostProcess;
			PixelShader = AdaptiveSharpenP1;
		}
	}
}

So if Adaptive_Toggles returns 1, then the passes would be skipped and the technique would be empty and would complete without actually processing the passes. Would something like that be possible, or do techniques have to successfully make some pass call?

Of course, all of this means adding the framerate adaptive code (or at least part of it) to each shader in one form or another in any case. I was hoping to avoid that, but it sounds like there isn't any other option.

Thanks, Crosire, for the info, and hopefully you (and/or someone else) can clarify regarding my other questions above.

Later,
Drake

P.S. Sorry if that seemed a bit rambling and disorganized. Like I said, my brain doesn't feel like it's working correctly right now.
The administrator has disabled public write access.

Issues with flow control... please help... 11 months 3 weeks ago #6

  • crosire
  • crosire's Avatar
  • Offline
  • Posts: 2438
  • Thank you received: 1387
en.wikipedia.org/wiki/Preprocessor vs en.wikipedia.org/wiki/Compiler

Code has to be inside functions, these functions can then be executed. If that function is returning void does not matter, it can always return (void functions simply return nothing).
A technique is just an effect description, telling ReShade how and when which functions are supposed to be executed. They cannot contain any code. Anything apart from function defintions, technique definitions or global variable definitions is not valid in a shader source file, so that's why your example won't work.

To execute code, place it in the main pixel shader function for whatever effect you want to disable:
const float MinFPSThreshold = 30.0f;
const float ToggleThreshold = (1000.0f / MinFPSThreshold);
...
void AdaptiveSharpenP0(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 edgeR : SV_Target0) {
    if (RFX_FrameTime > ToggleThreshold)
    {
        edgeR = float4(0, 0, 0, 0);
        return;
    }
    ...
}
...
float4 AdaptiveSharpenP1(float4 vpos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target {
    if (RFX_FrameTime > ToggleThreshold)
    {
        return tex2D(RFX_backbufferColor, texcoord);
    }
    ...
}
...
Cheers, crosire =)
Last Edit: 11 months 3 weeks ago by crosire.
The administrator has disabled public write access.

Issues with flow control... please help... 11 months 3 weeks ago #7

OK, I understand now. Thanks very much Crosire.

Later,
Drake
The administrator has disabled public write access.

Issues with flow control... please help... 11 months 3 weeks ago #8

  • piltrafus
  • piltrafus's Avatar
  • Offline
  • Posts: 72
  • Thank you received: 15
Crossire,
is the toggle option only for keystrokes or can we actually use some sort of a variable value to activate or deactivate it?.
for example, the first shader pass could detect the framerate and set a "#define TOGGLE_FX 0" for example and then we could use this in the technique to deactivate selectively without recompile:
technique Framework < enabled = RFX_Start_Enabled; toggle = TOGGLE_FX; >

does it make any sense?
The administrator has disabled public write access.

Issues with flow control... please help... 11 months 3 weeks ago #9

  • crosire
  • crosire's Avatar
  • Offline
  • Posts: 2438
  • Thank you received: 1387
A shader can never write to variables, it can only read from them (that's why they are referred to as uniforms or constants, because they are constant and the same for every pixel the shader is executed on. Remember, each shader is executed thousands of times per frame, for every single pixel on your screen.). Additionally a shader = a function, it does not know anything about the concept of techniques. Those are a managed level higher. And even further, annotations (the stuff between "<" and ">") are managed yet a level higher, so even the rendering backend does not know anything about them. So nope, that does not work.
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: piltrafus

Issues with flow control... please help... 11 months 3 weeks ago #10

crosire wrote:
To execute code, place it in the main pixel shader function for whatever effect you want to disable:

The code you posted has the constants defined outside of the functions. Wouldn't the compiler then consider them to be global, and thus complain (via critical warning) that they are uniform by default? Would such warnings be allowable, even though they are critical warnings?

Or should the const definitions be placed in each function that is modified, just above the if check against RFX_FrameTime?

Just would like a little clarification, please.

Also, I'm now getting a slew of additional errors I haven't seen before:
10/12/2015 18:10:51:695 [07172] | ERROR | Failed to compile effect on context 065E84F0:

C:\Program Files (x86)\Guild Wars 2\Shader@0x213FA8E0(23,10): warning X3571: pow(f, e) will not work for negative f, use abs(f) or conditionally handle negative values if you expect them
C:\Program Files (x86)\Guild Wars 2\Shader@0x213FAC58(27,10): warning X3571: pow(f, e) will not work for negative f, use abs(f) or conditionally handle negative values if you expect them
C:\Program Files (x86)\Guild Wars 2\Shader@0x213FB348(16,11): error X3003: redefinition of '__Sampler_NSRFX_backbufferColor'
C:\Program Files (x86)\Guild Wars 2\Shader@0x213FC550(16,11): error X3003: redefinition of '__Sampler_NSRFX_backbufferColor'
C:\Program Files (x86)\Guild Wars 2\Shader@0x213FD0E0(16,11): error X3003: redefinition of '__Sampler_NSRFX_backbufferColor'
C:\Program Files (x86)\Guild Wars 2\Shader@0x213FB2D0(16,11): error X3003: redefinition of '__Sampler_NSRFX_backbufferColor'
C:\Program Files (x86)\Guild Wars 2\Shader@0x213FC5C0(16,11): error X3003: redefinition of '__Sampler_NSRFX_backbufferColor'
C:\Program Files (x86)\Guild Wars 2\Shader@0x213FD7C8(16,11): error X3003: redefinition of '__Sampler_NSRFX_backbufferColor'

Since the errors simply refer to a memory location, and not a shader file, I don't see how I can locate where the problems are. For the "pow(f" errors, I can do a find in files for "pow(" and then simply address the locations where it isn't followed by "abs(". Though I'm rather reluctant to do that since I know that this issue will not cause the compiler to fail, it occurs all the time, and in some cases, it may be a problem to change it. But for the others, I don't know where to begin. I don't recognize any shader of "__Sampler_NSRFX_backbufferColor", and I don't recall anywhere that I would have tried to redefine RFX__backbufferColor, rather than merely calling it.

Is this because I placed my constants inside each function, along with my conditionals? Or is something else going on?

Once again, I'd appreciate some help with this.

Thanks,
Drake

P.S. I've been thinking about it, and I actually now like the idea of having each individual shader have to have the code present (for those that I want to affect this way, anyway). Because with them being separated that way, it would be possible to use a different FPS threshold for different shaders. So you could, if you wanted, set it up so that some shaders with less noticeable effects are disabled first, and then if FPS is still even lower, disable some others, and if still lower, then disable more again. Just thought I'd mention it.
Last Edit: 11 months 3 weeks ago by DrakePhoenix.
The administrator has disabled public write access.

Issues with flow control... please help... 11 months 3 weeks ago #11

OK, ignore my last, please.

I decided to delete all of my changes and start again more or less from scratch. I've been adding the code in to just a few shaders at a time, then testing the changes. So far everything is working fine except for SMAA and FXAA, both of which are causing some brightening when they toggle off, which causes severe flickering when the FPS is hovering close to the threshold, both above and below, so that the shaders toggle on and off repeatedly in short succession. I think this is probably because I'm returning the RFX_backbufferColor texture, and they need to actually return something else instead. Not sure though.

I'll work on that problem tomorrow. But for now, time for bed.

Later,
Drake
The administrator has disabled public write access.

Issues with flow control... please help... 11 months 3 weeks ago #12

  • Ganossa
  • Ganossa's Avatar
  • Offline
  • 최정장군
  • Posts: 790
  • Thank you received: 838
Its a nice idea! I would suggest to tackle shader which offer quality options that affect performance. You should be able to easly toggle between those without expecting artifacts.
To reduce flickering you might also want to consider two thresholds (upper and lower) so it does not flicker from one to another.

Since it seems to be part of existing shader code, it might be good to submit your changes to github so each dev can have a look at his code changes. :)
The administrator has disabled public write access.