Jump to content

  • Log In with Google      Sign In   
  • Create Account

Making a texture render to itself


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 george7378   Members   -  Reputation: 1202

Like
0Likes
Like

Posted 16 February 2014 - 10:44 AM

Hi everyone,

 

I'm working with post-processing in HLSL, i.e. I pass a texture to my effect file containing the back buffer and I then render a sprite using my shader to create various effects. I am doing Gaussian blur right now which means that I need to use multiple steps:

 

- Render scene to texture

- Render a sprite with the texture blurred horizontally

- Render a sprite with the texture blurred vertically

 

I've seen a few tutorials which seem to imply that you should render the back buffer to one texture (let's call it t_A), then render the horizontal blur to another separate texture (which I'll call t_B), and then render the final sprite by sampling t_B to perform the vertical blur. However, I decided to try and do it with only one texture, and so my program renders the scene to the texture, then passes the texture straight into the shader to perform the horizontal blur, then immediately passes it straight back in to do the final vertical blur, all without changing the render target (and all within the same BeginScene() and EndScene() pair).

 

So my question is: is it safe to make a texture sample itself in my shader while also rendering onto itself? Of course I pass the texture into the shader before I start drawing again, so I guess it's stored in there, but there must be a reason why the tutorials are using different textures to do different parts of the post-processing.

 

Thanks!



Sponsor:

#2 Tom KQT   Members   -  Reputation: 1590

Like
3Likes
Like

Posted 16 February 2014 - 12:00 PM

Did you actually try it? You would realise that it's not possible at all ;)

So yes, there is a good reason why everybody is using two render targets (textures) ;) You need just two even for many post-processing steps if you apply a ping-pong method (render to A, sample A and render to B, sample B and render to A, sample A and render to B....), but you need at least two.

You cannot read from a texture which currently is assigned as a render target.



#3 george7378   Members   -  Reputation: 1202

Like
0Likes
Like

Posted 16 February 2014 - 12:50 PM

Heh, it works when I try it! Here's a horizontal blur, vertical blur and greyscale effect rendered with just one render target:

 

rendering_bw_blur.png

 

Here's what I'm doing:

 

1. Set the offscreen texture as the render target, clear it, begin scene

2. Render the scene in colour, un-blurred, to the offscreen target

3. Immediately send the offscreen texture to the shader and render a sprite by sampling the texture to add the horizontal blur

4. Repeat for the vertical blur

5. End the scene and set the back buffer as the render target

6. Render a sprite to the back buffer by sampling the double-blurred texture using the greyscale shader

7. Present the back buffer

 

...should this be happening?? tongue.png

 

EDIT: I get this though when I run in debug mode:

 

Direct3D9: (WARN) :Can not render to a render target that is also used as a texture. A render target was detected as bound, but couldn't detect if texture was actually used in rendering.

 

Does this mean that it's actually using a different target? Funny how the effect still happens...


Edited by george7378, 16 February 2014 - 12:54 PM.


#4 unbird   Crossbones+   -  Reputation: 4981

Like
3Likes
Like

Posted 16 February 2014 - 01:08 PM

You're provoking undefined behaviour. A blur (or any effect which doesn't do a pixel/texel-perfect match) wouldn't even work if you actually could, so I really wonder if this is the correct result. 

 

Edit: Use a test-picture (e.g. a single white pixel on a black background) and a big kernel radius.



#5 C0lumbo   Crossbones+   -  Reputation: 2279

Like
1Likes
Like

Posted 16 February 2014 - 01:15 PM

I'd suspect that the driver is detecting the potentially trouble-causing situation and behind your back it's making a copy of the render target to use as the source texture. If that's the case you get correct rendering results on your machine, but there's no guarantee it'll work on any other driver/hardware and the copy means you get sub-optimal performance.

 

Just a guess though.



#6 kauna   Crossbones+   -  Reputation: 2515

Like
1Likes
Like

Posted 16 February 2014 - 01:24 PM

Typically if you try to bind a texture as a render target and it is bound as input in the same time, the binding will be released. 

You should enable debugging to see if there are any errors produced (there should be).

 

Cheers!



#7 wh1sp3rik   Members   -  Reputation: 248

Like
1Likes
Like

Posted 16 February 2014 - 02:30 PM

In this situation, I think it's better to create two textures. One for SRV and one for RTV. After you render into RTV, you can copy RTV to SRV with copyresource. It's should be fast as it's GPU to GPU. Also SRV and RTV should be set to default, so no CPU writing/reading.


DirectX 11, C++


#8 kauna   Crossbones+   -  Reputation: 2515

Like
1Likes
Like

Posted 16 February 2014 - 03:53 PM


In this situation, I think it's better to create two textures. One for SRV and one for RTV. After you render into RTV, you can copy RTV to SRV with copyresource. It's should be fast as it's GPU to GPU. Also SRV and RTV should be set to default, so no CPU writing/reading.

 

Copying between resources isn't necessary. You may use the same texture as render target and pixel shader resource, just not at the same time.

 

Cheers!



#9 L. Spiro   Crossbones+   -  Reputation: 13600

Like
3Likes
Like

Posted 16 February 2014 - 05:11 PM

Direct3D9: (WARN) :Can not render to a render target that is also used as a texture. A render target was detected as bound, but couldn't detect if texture was actually used in rendering.
 
Does this mean that it's actually using a different target? Funny how the effect still happens...

It means it is following the rules stating that a texture cannot be an input and an output at the same time and it is likely being unbound internally from either the output (render target) or the input (sampler) stage. Proceeding this way is undefined behavior, and no, your result is not correct just because you got a final image on the screen that isn’t a mess.


You are required to make 2 separate textures and ping-pong render between them.

Even if it did work, your results would be screwed up by it. A blur requires sampling neighbor texels. If you have modified those texels in real-time (by reading from the texture and writing directly back to it on each pixel, for example) then your following blur calls will no longer be sampling from the original data and instead will include previously blurred samples, which would corrupt your blur for the current sample.
So even if the hardware allowed you to read and write from/to a single source you would still need 2 textures. There is no getting around it.


L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#10 Hodgman   Moderators   -  Reputation: 30388

Like
1Likes
Like

Posted 16 February 2014 - 05:59 PM

It will work on *some* GPUs as long as you only sample from the current pixel (so greyscale filter is possible, but a blur filter is a potential race condition).
However, this is not possible on ALL GPUs, so D3D/GL are forced to disallow it and call it undefined behavior. Don't do it if you want your game to work on any PC configuration besides your current one...


Edited by Hodgman, 16 February 2014 - 09:31 PM.


#11 JohnnyCode   Members   -  Reputation: 219

Like
1Likes
Like

Posted 16 February 2014 - 09:21 PM

You are perhaps not combining the ouput of first horizontal pass, and you only sample original texture in creating vertical pass. Blending them will result in a blur, but not the exact gausian blur, since that demands the vertical dissorted texture to be sampled to generate horizontal one. But if result is satisfying and you are not doing an university assignment you can stick to it, since it is more optimized in terms of memory resources and state changes.



#12 george7378   Members   -  Reputation: 1202

Like
1Likes
Like

Posted 17 February 2014 - 07:24 AM

I've changed it so that I do the ping-pong rendering between two different textures. It's very little extra effort but it means that I can be guaranteed safe results (and I don't get the warning signs any more). When I render properly I get exactly the same result with the Gaussian blur as I I do with the single texture, so the GPU must be making a separate copy. Thanks for the help!






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS