- Posts: 62
- Forum
- Shaders & Effects
- Discussion
- Question about shader optimization (rendertarget to 1x1 texture for data)
Question about shader optimization (rendertarget to 1x1 texture for data)
- Daemonjax
-
Topic Author
- Offline
Less More
1 year 3 months ago - 1 year 3 months ago #1 by Daemonjax
Question about shader optimization (rendertarget to 1x1 texture for data) was created by Daemonjax
So, I was reading this old thread: reshade.me/forum/shader-presentation/230...ted-storybook-shader
... where crosire was describing a method to have a pixel shader pass run once per frame instead of once per pixel per frame :
Here's an idea for black border detection.
Running this on each pixel is probably inefficient and takes away performance, so instead you could calculate it only once and store the result in a texture to use later:
My questions:
Is this simply because the rendertarget is 1x1 pixel (which would explain why multiple rendertargets require the pixel dimensions to be the same)? So if we ONLY changed the texture to be 8x8 pixels, the shader would then run 64 times per frame (setting each pixel in the rendertarget to the same value)? So I guess there's always a rendertarget even when it's not explicit in the technique declaration, and the default rendertarget is what exactly? The next color buffer?
I'm always really paranoid on relying on compiller optimizations I don't fully understand. I could imagine it being dumb and just run 1920*1080 times per frame, setting the same exact pixel in the 1x1 rendertarget to the same value and I'd be none the wiser. Are there any gotchas to this approach?
... where crosire was describing a method to have a pixel shader pass run once per frame instead of once per pixel per frame :
Warning: Spoiler!
Here's an idea for black border detection.
texture colorTex : COLOR;
sampler colorSamp { Texture = colorTex; };
// x = left or image without black borders, y = top, z = right, w = bottom
float4 CalculateViewport()
{
float4 viewport = float4(0, 0, 1, 1);
// Look through the pixels on x and y axis until one that is not black is found.
while (dot(tex2D(colorSamp, float2(viewport.x, 0.5))) > 0 && viewport.x < 1)
{
viewport.x += BUFFER_RCP_WIDTH;
}
while (dot(tex2D(colorSamp, float2(viewport.y, 0.5))) > 0 && viewport.y < 1)
{
viewport.y += BUFFER_RCP_HEIGHT;
}
// Let's asume the black bars are mirrored across the screen
viewport.z = 1 - viewport.x;
viewport.w = 1 - viewport.y;
// Return our gathered information. It's a rectangle containing the position and size of our image without black borders.
return viewport;
}
Running this on each pixel is probably inefficient and takes away performance, so instead you could calculate it only once and store the result in a texture to use later:
texture viewportTex { Width = 1; Height = 1; Format = RGBA32F; };
sampler viewportSamp { Texture = viewportTex; MinFilter = POINT; MagFilter = POINT; };
float4 CalculateViewport(in float4 pos : SV_Position) : SV_Target
{
...
return viewport;
}
float4 SomeOtherShader(in float4 pos : SV_Position, in float2 texcoord : TEXCOORD) : SV_Target
{
// Retrieve our viewport information from the texture we rendered it to below.
float4 viewport = tex2D(viewportSamp, float2(0, 0));
// Lets just use it to discard/abort rendering in the black borders and only do stuff on the actual image.
if (texcoord.x < viewport.x || texcoord.y < viewport.y || texcoord.x > viewport.z || texcoord.y > viewport.w)
{
discard;
}
float4 color;
...
return color;
}
technique MyTechnique
{
pass
{
// Render the result of the CalculateViewport function into a texture ("viewportTex") only once (at start of post processing).
VertexShader = ...;
PixelShader = CalculateViewport;
RenderTarget = viewportTex;
}
pass
{
// Now we can execute other shaders and use the result stored inside "viewportTex".
VertexShader = ...;
PixelShader = SomeOtherShader;
}
}
My questions:
Is this simply because the rendertarget is 1x1 pixel (which would explain why multiple rendertargets require the pixel dimensions to be the same)? So if we ONLY changed the texture to be 8x8 pixels, the shader would then run 64 times per frame (setting each pixel in the rendertarget to the same value)? So I guess there's always a rendertarget even when it's not explicit in the technique declaration, and the default rendertarget is what exactly? The next color buffer?
I'm always really paranoid on relying on compiller optimizations I don't fully understand. I could imagine it being dumb and just run 1920*1080 times per frame, setting the same exact pixel in the 1x1 rendertarget to the same value and I'd be none the wiser. Are there any gotchas to this approach?
Last edit: 1 year 3 months ago by Daemonjax.
Please Log in or Create an account to join the conversation.
- Daemonjax
-
Topic Author
- Offline
Less More
- Posts: 62
1 year 3 months ago #2 by Daemonjax
Replied by Daemonjax on topic Question about shader optimization (rendertarget to 1x1 texture for data)
Or would I still need to include a
if (texcoord.x != 0.5 && texcoord.y != 0.5) discard;
?
if (texcoord.x != 0.5 && texcoord.y != 0.5) discard;
?
Please Log in or Create an account to join the conversation.
- crosire
-
- Away
Less More
- Posts: 4056
1 year 2 months ago #3 by crosire
Replied by crosire on topic Question about shader optimization (rendertarget to 1x1 texture for data)
Your pixel shader is generally executed once for every pixel, so if you only have one pixel to render to (1x1 render target), it's only executed a single time (your if statement would have no effect, since it would never be hit). With a 8x8 render target it would run 64 times, yes (just keep in mind that it does run in parallel, not serialized, so big numbers here are not a problem).
There is always a render target, it's just that ReShade FX has syntactic sugar in that not explicitly setting a "RenderTarget" pass state will default to the back buffer (the buffer the game rendered the final image to).
There is always a render target, it's just that ReShade FX has syntactic sugar in that not explicitly setting a "RenderTarget" pass state will default to the back buffer (the buffer the game rendered the final image to).
Please Log in or Create an account to join the conversation.