Advertisement Jump to content

2D HLSL - Sample the backbuffer I'm rendering to

Recommended Posts

In MonoGame I'm writing a shader for lighting and shadows in a 2D Platformer.

A shadow will be drawn for each character for each light that hits said character. Because shadows from different lights can overlap the shadows are drawn to a texture where each pixel is a bitfield where each bit tells you if the pixel was reflected by a given light. In the lighting shader for each light, it only applies light if the bit for that light is not set at the given pixel.

In order to not make for example 40 draw calls to draw 40 shadows if 40 lights overlapped a character, I batch shadows together into a VertexBuffer with the data specifying which light created the given shadow. In the shadow shader, it samples the render target I am drawing the shadows to and sets its own bit. My problem is that the changes from the previous shadows in the same batch aren't applied to the render target until after the draw call has completed. This results in the bitfield getting overwritten by shadows from other lights.

If I could somehow sample the back buffer this wouldn't be a problem. Is there any way I can fix this without making a draw call for each shadow?

Edited by CSharpCoder

Share this post

Link to post
Share on other sites

Unfortunately, generally, you cannot read a texture aliased to the memory of a render-target you're writing to in that very draw-call. The reasons include:

* the order of individual pixels being shaded can't be predicted

* the cache hierarchy used to write RTVs and read SRVs can (and will be) different - cache flushing to main memory is needed

So you have all kinds of hazards.

Share this post

Link to post
Share on other sites

There's a special case though, where reading and writing to the same texture are possible (on some architectures?):

  1. it's a single draw-call over the whole texture (no overdraw)
  2. the previous writes to the memory have already settled in the main memory
  3. every pixel shader reads only its own pixel (and no other pixels!)
  4. the results of this draw-call become usable only after all pixels have finished executing and everything has settled in the main memory

Point 2) is important for point 3), in order to not read stale values. This also goes for compute shaders.

Edited by pcmaster

Share this post

Link to post
Share on other sites

Instead of having the pixelshader write to a rendertarget, you could have the pixelshader write to a texture UAV.

It would allow your pixel shader to both read and write pixels. You may have to use interlocked functions.

So if you want to set a certain bit on a pixel, you could InterlockedOr with a number that just has that bit set.


Edited by CortexDragon

Share this post

Link to post
Share on other sites

InterlockedOr requires shader model 4.0, don't know what you mean by texture UAV.

Although I found a perfect solution for my specific case.

I can just use additive blending among the shadows being drawn in the same batch because they are all created by different lights, which will create the same result as using bitwise OR
1 + 2 = 1 | 2 = 3, however if the bit is already set 2 + 2 ≠ 2 | 2 = 2 

It will still need to sample the shadows from other characters and check if the bit is already set, if that's the case it should return 0 (add 0), otherwise, return light bit for the shadow.

Edited by CSharpCoder

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement

Important Information

By using, you agree to our community Guidelines, Terms of Use, and Privacy Policy. is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!