Jump to content
  • Advertisement
Sign in to follow this  
BattleMetalChris

Encoding eight halfs into four floats

This topic is 2600 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

[font="Helv"][font="Helv"]I have a pixel shader that outputs 8 floats and needs to store them in a rendertarget for use as input into a second pass. I don't mind losing a bit of precision, so I was thinking of encoding them into four lots of two half-precision floats and just putting these into the RGBA slots of the render target, which is R32B32G32A32.

To store the two halfs in a float is it just a case of doing



float fvar1;

float fvar2;

//stuff to give them values

half hvar1 = fvar1;

half hvar2 = fvar2;

float output = (float)hvar1 + ((float)hvar2 << 16);



like you would if you were using ints, or is bitshifting floating point variables a bit more complicated than that?

Or, can I just declare a half8 and bitwise copy the entire contents into a float4?

[/font][/font]

Share this post


Link to post
Share on other sites
Advertisement
I would just make 2 pixel shaders writing to 2 rendering targets to be sure that it is working even if the user force the graphics card to work with a higher bit depth in the future.

Share this post


Link to post
Share on other sites
Well, the reason I'm doing it like this is to try and reduce texture reads for the next step (currently 27 per pixel). If I use two render targets, it would double this, as well as messing about having to swap them about.

Share this post


Link to post
Share on other sites
Maybe you could do it by scaling one of the components to always between 0 and 1 (for instance), and the other so that it's always a *whole number* between 0 and 100000. Then add them together.

Then in the pixel shader if you have a number like 746.123, you know your two values are 746 and 0.123 (and then you can scale them back accordingly to their actual values).

Of course you need to ensure your data is always between those values. And you'll end up facing some precision issues I'm sure. For instance, while there are millions of possible values between 0 and 1, there are only a few hundred between 60000 and 60001, for instance (so the precision of your first component will suffer if the value of your second component gets big). The precision issues may be insurmountable, but its just a thought.

And of course if your pixel shader is doing anything put point sampling from this texture, none of this will work because interpolation between different values won't work correctly.

Share this post


Link to post
Share on other sites
Well, the reason I'm doing it like this is to try and reduce texture reads for the next step (currently 27 per pixel). If I use two render targets, it would double this, as well as messing about having to swap them about.
In the first pass, you can output to 2x RGBA16F (via MRT), instead of 1x RGBA32F (With 8 16F's packed into it).

In the second pass, yes you require two texture loads to fetch this data, but each of those loads is half the size. The total amount of bandwidth required by the fetches is the same in either case ([font="Courier New"]2 * 4 *16 == 1 * 4 * 32[/font]).

Share this post


Link to post
Share on other sites
I've not used MRT before, but looking at a few examples it actually looks pretty simple to implement :)

How do I output to the 16-bit surfaces from the Pixel shader? Do I still use float4 for each SV_Target or do I need to use half4?

Share this post


Link to post
Share on other sites
How do I output to the 16-bit surfaces from the Pixel shader? Do I still use float4 for each SV_Target or do I need to use half4?
You can use either, and they'll be converted to 16-bit floats.

Remember that traditionally render-targets have been 8-bit, but shaders can still output floats (where 0.0f->0 and 1.0f->255), and that likewise, you can sample from an 8-bit texture and receive the result as a float4 (where 0->0.0f and 255->1.0f).

Share this post


Link to post
Share on other sites

I'm using OMSetRenderTargets, can you only have one depth stencil, regardless of the number of render targets?

The reason is that the scene is only being rasterized once, even though you are writing data to more than one render target. In effect, you are amplifying the data after rasterization, and hence only need one depth stencil buffer.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net 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!