Get bit depth of backbuffer?

  • pneumatic
  • Topic Author
More
4 years 10 months ago - 4 years 10 months ago #1 by pneumatic Get bit depth of backbuffer? was created by pneumatic
Hello

Can ReShade provide any information about the number of bits per pixel the game uses?

I use high precision floating point numbers in my shader, but in the end they will be typically rounded to the nearest 8-bit value since that is what most games tend to render at.

However some (HDR?) games may use 10 bits and I'd like to be able to detect that, as it affects how my shader needs to work.

I looked at
github.com/crosire/reshade-shaders/blob/master/REFERENCE.md
but couldn't see anything there.

Thanks
Last edit: 4 years 10 months ago by pneumatic.

Please Log in or Create an account to join the conversation.

  • crosire
More
4 years 10 months ago #2 by crosire Replied by crosire on topic Get bit depth of backbuffer?
This is on the TODO list, but not yet possible.
The following user(s) said Thank You: Bloody Eugene

Please Log in or Create an account to join the conversation.

  • pneumatic
  • Topic Author
More
4 years 10 months ago #3 by pneumatic Replied by pneumatic on topic Get bit depth of backbuffer?
Thanks.

In that case I will just define a var which the user can set, eg. 8|10|12 etc. to match whatever the game happens to use.

A couple of extra questions if I may:

1. When using ReShade with a game that renders in 10 bits (eg. HDR games) does ReShade preserve the 10-bit value through its pipeline, or does it round to 8-bit at some point? I have no 10-bit games or monitor to test with.

2. Is it the bit depth of the back buffer or the front buffer which determines the bit depth of the final colour drawn to screen?

Thanks

Please Log in or Create an account to join the conversation.

  • crosire
More
4 years 10 months ago #4 by crosire Replied by crosire on topic Get bit depth of backbuffer?
1) If the game uses a 10bit backbuffer, ReShade will use the same format for its internal buffers too. So yes, the precision is preserved throughout the pipeline.
2) The frontbuffer should implicitly be created with the same format as the backbuffer (one has no control over this, it is handled by the driver). So if a game requests a 10bit backbuffer, that's what will be used for presentation. But starting with Windows 10 things become a bit more complicated, because there is an additional layer between DX/GL and monitor scanout now (DWM). All the new HDR settings in the Windows Settings now affect how that layer interprets the data before it is finally sent off to your monitor.
The following user(s) said Thank You: pneumatic

Please Log in or Create an account to join the conversation.

  • pneumatic
  • Topic Author
More
4 years 10 months ago - 4 years 10 months ago #5 by pneumatic Replied by pneumatic on topic Get bit depth of backbuffer?
Thanks
Also does the current version of ReShade still round to the backbuffer format after each effect in the pipeline?
Last edit: 4 years 10 months ago by pneumatic.

Please Log in or Create an account to join the conversation.

  • crosire
More
4 years 10 months ago #6 by crosire Replied by crosire on topic Get bit depth of backbuffer?
It uses the same buffer as the game does, so yeah.
The following user(s) said Thank You: pneumatic

Please Log in or Create an account to join the conversation.

  • pneumatic
  • Topic Author
More
4 years 10 months ago #7 by pneumatic Replied by pneumatic on topic Get bit depth of backbuffer?
I noticed in version 2, CeeJay's SweetFX suite avoided that by including several effects in one effect file, which preserved the high precision values between each of his effects, which made it possible for him to use dithering on those final high precision values to avoid banding artefacts on all his effects.

If ReShade could preserve the high precision values through its entire pipeline, this would open up the possibility of having the same kind of high quality dithering and smooth gradients on all effects.

There are currently ways to achieve smooth gradients on all effects, such as applying FilmGrain as the first effect in the pipeline, or applying the Deband shader as the last effect, but these aren't optimal methods and have their drawbacks. Basically dithering works best when operating on high precision values as the very last effect in the pipeline.

Is it trivial to allow preservation of high precision values between effects, or would that require rewriting a lot of stuff?

Cheers

Please Log in or Create an account to join the conversation.

  • TreyM
More
4 years 10 months ago - 4 years 10 months ago #8 by TreyM Replied by TreyM on topic Get bit depth of backbuffer?
Actually, you really want to dither BEFORE effects that cause banding from truncation by reshade to RGBA8 for best results. But, that needs to be done within the shaders or functions themselves as CeeJay did like you've already mentioned.
Last edit: 4 years 10 months ago by TreyM.

Please Log in or Create an account to join the conversation.

  • pneumatic
  • Topic Author
More
4 years 10 months ago - 4 years 10 months ago #9 by pneumatic Replied by pneumatic on topic Get bit depth of backbuffer?

TreyM wrote: Actually, you really want to dither BEFORE effects that cause banding for best results.


The effects themselves don't cause banding though, because they are done with high precision floating point values.
Take CeeJay's Curves shader for example, it produces high precision S-curve using mathematical formulas.
But after the effect is finished, ReShade rounds the final value to the backbuffer format, which causes the banding.
Then the next effect comes along, does its thing, then it too gets rounded to backbuffer format.
Ideally we should preserve the high precision value all the way till the very end, and then apply dithering to it at the very last step to convert high precision to low precision to suit the backbuffer format.
Comment from CeeJay's shared.h: // Dither (should go near the end as it only dithers what went before it)
Last edit: 4 years 10 months ago by pneumatic.

Please Log in or Create an account to join the conversation.

  • crosire
More
4 years 10 months ago #10 by crosire Replied by crosire on topic Get bit depth of backbuffer?
The way you do it is to create a texture with a format that stores the precision you want and use that as render target between passes. That guarantees precision to what you want. RGBA8 is the standard image format and this the one ReShade will use most if the time. If you need more precision you have to opt-in to that yourself the way I described.

Please Log in or Create an account to join the conversation.

  • pneumatic
  • Topic Author
More
4 years 10 months ago #11 by pneumatic Replied by pneumatic on topic Get bit depth of backbuffer?

crosire wrote: The way you do it is to create a texture with a format that stores the precision you want and use that as render target between passes. That guarantees precision to what you want. RGBA8 is the standard image format and this the one ReShade will use most if the time. If you need more precision you have to opt-in to that yourself the way I described.


Is it possible to do that between techniques as well?

Please Log in or Create an account to join the conversation.

  • crosire
More
4 years 10 months ago #12 by crosire Replied by crosire on topic Get bit depth of backbuffer?
Yes, absolutely. Textures are preserved. See the Splitscreen or UIMak shader as an example, which does exactly that.
The following user(s) said Thank You: pneumatic

Please Log in or Create an account to join the conversation.

  • TreyM
More
4 years 10 months ago - 4 years 10 months ago #13 by TreyM Replied by TreyM on topic Get bit depth of backbuffer?

pneumatic wrote: The effects themselves don't cause banding though, because they are done with high precision floating point values.


I'm aware of this, however you can have all the precision you want and it's still going to cause banding due to truncation. Certain effects DO cause banding due to the output being truncated to 8 bit, such as vignette for example. You need to dither within the function/shader containing the effect before the truncation occurs which is what causes banding.

If you want to avoid banding on an 8-bit display on subtle gradients, you're going to need to dither at some point. There is no escaping it.

Some relevant reading here: loopit.dk/banding_in_games.pdf
Last edit: 4 years 10 months ago by TreyM.

Please Log in or Create an account to join the conversation.

  • pneumatic
  • Topic Author
More
4 years 10 months ago #14 by pneumatic Replied by pneumatic on topic Get bit depth of backbuffer?

TreyM wrote: Certain effects DO cause banding due to the output being truncated to 8 bit, such as vignette for example.


Vignette doesn't actually cause banding though. What I mean by that exactly, is that nowhere in VignettePass() does it round or truncate to the nearest bit step. The gradients it generates for the corners of the screen are mathematically smooth and continuous, limited only by the number of decimal places in the floating point values it uses, which is large and precise. The rounding occurs later on in the Technique section, due to ReShade rounding VignettePass to the backbuffer format since its Technique specifies no render target, which defaults to the backbuffer target which is typically RGBA8. The proof is that when CeeJay's dither.h shader is enabled (ReShade v2.0) it creates a perfectly smooth vignette gradient, otherwise there would be nothing to dither "from", and all we'd be doing is adding noise to the already "baked in" banding artefacts which Vignette created (because remember, CeeJay's dither shader is applied AFTER the vignette).

crosire wrote: Yes, absolutely. Textures are preserved. See the Splitscreen or UIMask shader as an example, which does exactly that.


Thanks, it works :)

Please Log in or Create an account to join the conversation.

  • pneumatic
  • Topic Author
More
4 years 10 months ago - 4 years 10 months ago #15 by pneumatic Replied by pneumatic on topic Get bit depth of backbuffer?
Spoke too soon :silly:

It seems multiple techniques can't use the same texture as their render target, otherwise I get a raster full of black pixels.
I can get around it by rendering to a different texture for each pass in the pipeline, but it requires creating 50 textures (1 for each effect) and I'm not sure it's feasible performance wise.

https://github.com/crosire/reshade-shaders/blob/master/REFERENCE.md wrote: // Be aware that you can only read **OR** write a texture at the same time, so do not sample from it while it is still bound as render target here.
// Clears all bound render targets to zero before rendering when set to true.
ClearRenderTargets = true;


I tried adding ClearRenderTargets = true; but it gives me error: unrecognized pass state 'ClearRenderTargets'.

edit: ah, because ClearRenderTargets was only added in v3.0 and I'm testing on v2.0 atm.

But I'm still not sure this is the problem, as it would seem I'm not reading/writing to the texture at the same time.
Last edit: 4 years 10 months ago by pneumatic.

Please Log in or Create an account to join the conversation.

  • pneumatic
  • Topic Author
More
4 years 10 months ago #16 by pneumatic Replied by pneumatic on topic Get bit depth of backbuffer?
Just to clarify what I'm trying to do, to confirm it should be possible with just one texture:


texture RFX_backbufferTex_RGBA16F { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; Format = RGBA16F;};
sampler RFX_backbufferColor_RGBA16F { Texture = RFX_backbufferTex_RGBA16F; };



float4 Shader1(float4 vpos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
{
	float4 color = tex2D(RFX_backbufferColor, texcoord);	
	return color;
}
technique Tech1 
{
	pass Pass1
	{
		VertexShader = RFX_VS_PostProcess;
		PixelShader = Shader1;
		RenderTarget = RFX_backbufferTex_RGBA16F;	
	}
}




float4 Shader2(float4 vpos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
{
	float4 color = tex2D(RFX_backbufferColor_RGBA16F, texcoord);	
	return color;
}
technique Tech2 
{
	pass Pass2
	{
		VertexShader = RFX_VS_PostProcess;
		PixelShader = Shader2;
		RenderTarget = RFX_backbufferTex_RGBA16F;	
	}
}





float4 Shader3(float4 vpos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
{
	float4 color = tex2D(RFX_backbufferColor_RGBA16F, texcoord);	
	return color;
}
technique Tech3 
{
	pass Pass3
	{
		VertexShader = RFX_VS_PostProcess;
		PixelShader = Shader3;
	}
}

Please Log in or Create an account to join the conversation.

  • crosire
More
4 years 10 months ago #17 by crosire Replied by crosire on topic Get bit depth of backbuffer?
You cannot read from and write to the same texture in a pass. The only exception is the backbuffer because ReShade automatically manages a mirror texture there for you. If you use custom textures you need to ping/pong between two different ones (read from the first and write to the second, then read from the second and write to the first etc.).
The following user(s) said Thank You: pneumatic

Please Log in or Create an account to join the conversation.

  • Marty McFly
More
4 years 10 months ago #18 by Marty McFly Replied by Marty McFly on topic Get bit depth of backbuffer?
Any color processing stuff is being computed in float format usually, so when still inside a pixel shader, the data isn't quantized (at least not visibly).
To actually apply whatever is being computed, the shader renders to the backbuffer, which means quantization to 8 or 10 bit per channel, depending on backbuffer format, and that causes banding.
Vignette is bound to create banding, it creates wide gradients with only a few colors between start and end and many more pixels between start and end. The only real way to add dithering is add it right before the shader outputs to the backbuffer, where it would get quantized. So basically inside each shader, at the end.

CeeJay's dither shader is inside the same pixel shader as the vignette on ReShade 2.0, so that's exactly how it's supposed to be used. On current version with Vignette being an independent filter and rendering to backbuffer before any dither can do anything, dither does nothing to help banding form the vignette.

Please Log in or Create an account to join the conversation.

  • TreyM
More
4 years 10 months ago #19 by TreyM Replied by TreyM on topic Get bit depth of backbuffer?
Well unless it's inside the vignette function as you said. The current TriDither shader is apparently useless because of this, and I'm going to do a pull request to make it a callable function instead of a shader as it is now. Once that's done, we can add the dither function call to problematic effects, then we can (in theory if crosire is in favor) optionally toggle "dithering" globally via preprocessor definition.

Please Log in or Create an account to join the conversation.

  • pneumatic
  • Topic Author
More
4 years 9 months ago - 4 years 9 months ago #20 by pneumatic Replied by pneumatic on topic Get bit depth of backbuffer?

crosire wrote: You cannot read from and write to the same texture in a pass. The only exception is the backbuffer because ReShade automatically manages a mirror texture there for you. If you use custom textures you need to ping/pong between two different ones (read from the first and write to the second, then read from the second and write to the first etc.).


I'm not sure if this is possible for the entire pipeline, as the user could enable any random order of effects, so each effect needs to update a global var to keep track of the last used texture, and we need to check that value with an if statement inside the technique's pass, which appears to be invalid syntax. Is there some way around this like dereferencing a string like RenderTarget = %GlobalStringContainingNameOfTextureVariable%
Last edit: 4 years 9 months ago by pneumatic.

Please Log in or Create an account to join the conversation.

We use cookies
We use cookies on our website. Some of them are essential for the operation of the forum. You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.