Accessing MSAA texture

I am trying to access/resolve the MSAA Render Texture/Target in a custom fullscreen pass / image effect. However, when I declare my Texture2DMS in my shader, I get the following error:

Shader error in 'Custom/customres': Fragment program 'frag': unrecognized sampler type msaaTex (on d3d11)

Does Unity support Texture2DMS access? Am I missing something in my declaration?
System: Windows / HLSL / SM 5.0

Shader "Custom/customres"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM

            #pragma target 5.0
            #pragma only_renderers d3d11

            #pragma vertex vert
            #pragma fragment frag
           
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
           
            //sampler2D _MainTex;
            Texture2DMS<float4, 4> msaaTex : register(t0);

            float4 frag (v2f i) : SV_Target
            {
                float4 col;
           
                // this doesn't work
                col = msaaTex.Load(0, 0);

                return col;
            }
            ENDCG
        }
    }
}

Hi there,

I am now stuck with the same issue, after a bit of research it seams that Unity will force the MSAA resolve BEFORE you bind your MSAA texture to your shader, and as a result you won’t have access to the sample data because a MSAA depth texture simply cannot be resolved, not a bug thats just how it is defined.

That’s a huge pity in my case because I’m rendering in MSAA for VR, but I don’t have any way to access the depth buffer I just rendered my geometries in.

The only work around ATM is to NOT use MSAA or to force the camera to re-render the scene in a non-MSAA texture using Camera.depthTextureMode (easy fix if your scene is simple) and then use the texture “_CameraDepthTexture” in your shader (the texture will get automatically attached to your shader for you behind the scenes).

But in my case that is not possible because my scenes are very complex and I can’t afford rendering the scene twice (CAD scenario).

I would love to hear from Unity gurus to know if there is a solution to that problem maybe @Aras ?

At the moment I am thinking of writing a native C++ plugin to copy the only a single sample channel from a MSAA to a non-MSAA texture behind the scene, but if there would be a simpler hack I would be so happy…

ta.

Hi, do you find out some way to solve the problem ? I came into the same problem.And My scene is also complex so it’s too expensive to use the depthTextureMode.

I know this is solved for the SRPs as it ships with a depth blit shader that’ll sample from an MSAA depth to a non-MSAA target.
https://github.com/Unity-Technologies/ScriptableRenderPipeline/blob/9f190144c7b0131d55621f25ae0830c74b0d991b/com.unity.render-pipelines.universal/Shaders/Utils/CopyDepthPass.hlsl

And you can tell a MSAA render texture to not resolve to a non-MSAA target when used as a texture property.

Theoretically this should be usable for the built in renderer, though you’ll probably need to use your own render textures and set the camera’s buffers yourself.

1 Like

Thanks for your reply. Our project is using the 2018.1.6 version. And the doc for 2018.1 says that the SRPs is in preview, so I guess it’s unsafe to use it for our project.

Just an FYI: The current implementation of URP/LWRP falls back to a depth pre-pass (which is serious perf hit for us) due to this line:
// TODO: We don’t have support to highp Texture2DMS currently and this breaks depth precision.
// currently disabling it until shader changes kick in.
In forwardrenderer.cs

I have gotten the copy to work, but I am not sure how reliable it will be across devices.
For example on DX, you can auto-resolve the depth buffer (I am not sure what operation it does to combine 4 depths into 1)
On mobile, we have to resolve the whole MSAA depth surface to memory and access it as a Texture2DMS<float, samples>. This is expensive but it seems less expensive than the depth pre-pass.

@DavidSWu this TODO is outdated. Can you please report a bug so that we fix this?
Support for precision postfixes for all variants of textures is there since 2018.3.0a2 :slight_smile:

Thank you for the information, I will report it!
What exactly are the precision postfixes?
We use Texture2DMS<float,4>, are we getting low precision results?
Also are there ways to get 4 pixels at a time? Either the 4 MSAA samples or a form of Gather4 that works on an MSAA index?
Thanks!

You can use all of the Texture* (Texture2D, Texture3D and all others) with “_half” or “_float” postfixes, e.g.
Texture2DMS_float<float, 4>.
Unity 2020.1 extracts information from “<float, 4>”, so it shouldn’t be required there anymore.

Before Unity 2020.1, yes.

Seems like there’s no support for this in HLSL: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-to-gather

Thank you alek for the responses!

I don’t think that this is still the case.
While resolving a depth buffer is not well defined (there is no obvious operation to use, i.e. average, an average of reciprocals, max, etc. ), it seems to be supported on a growing number of platforms.

If you are only accessing the depth of the pixel that you are rendering to, and you are rendering at the same MSAA and resolution you might be about to use the RenderPass api. This seems like the most efficient solution by far.
However, I don’t know what platforms it will be natively supported on. It seems like with GLES it currently emulates with rendertargets and resolves. On Vulcan and Metal it is native.

Hello alek,
I found this TODO is still in ForwardRenderer.cs.

1 Like

This TODO is still inside the https://github.com/Unity-Technologies/Graphics/blob/master/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs#L850

May I hope to use MSAA with CopyDetphPass someday?

Has anyone successfully accessed MSAA data before resolve? I have not been successful using RenderTextureDescriptor.bindMS. When I blit the cameraColorTargetHandle to an RTHandle with this setting on its descriptor, I still appear to be getting resolved values for each pixel (i.e., each subsample value is identical to 8+ places). In contrast, when I readout pixel sample data from the cameraDepthTargetHandle, I DO get subsample data which varies between each sample. I cannot find any way to achieve the same results with color as opposed to depth.

@aleksandrk can anyone comment whether it is possible to copy out the full MSAA render target of the color buffer before it ever gets resolved? There is radio silence on this topic across the board.

@JSmithIR do you have Unity - Scripting API: RenderTextureCreationFlags.NoResolvedColorSurface enabled in the flags?

Thank you for your response @aleksandrk ! I have not seen this flag until now. Can you give an example of how to use this in a scriptable render pass? I tried to set it but an error says its read only. I do not see a RenderTexture or RenderTextureDescriptor constructor that will allow me to set this flag.

@JSmithIR It looks like you should be able to set the flags on the RenderTextureDescriptor before creating the RenderTexture with it.

How do I set the flags on theRenderTextureDescriptor though? If i do something like descriptor.flags = RenderTextureCreationFlags.NoresolvedColorSurface then I get an error saying that flags are read-only. And again, I cannot find a constructor for RenderTextureDescriptor that takes this flag as an argument

Oh, indeed, it looks like there’s no way to set it currently.
I would suggest to report a bug then.

1 Like