Framebuffer Fetch not working on Vulkan?

Hi,

I’ve got a simple shader together that works with Framebuffer Fetch on openGL just fine. However, when I switch to Vulkan, Framebuffer Fetch is no longer working.

I suspect this is because Vulkan’s implementation is different (i.e. its part of Vulkan subpasses) - but I am not clear on this.

Additionally, as far as I can find out through searches, Vulkan subpasses do not work on mobile XR devices using the URP (Quest 2+ is the target platform). I can’t find concrete evidence, but I’m not familiar with how to write custom passes & subpasses enough to test myself.

Can anyone shed any more light on this or offer any help in either getting Framebuffer Fetch working on Vulkan in some form, or point me in a direction?

Here is the shader:

Shader "Unlit/OculusQuestFrameBufferFetch"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", color) = (0.0,1.0,0.0)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="AlphaTest+10"}
        LOD 100
        Pass
        {
            CGPROGRAM
            #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;
            };
            sampler2D _MainTex;
            float4 _MainTex_ST;
            half4 _Color;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
            void frag(v2f i, inout fixed4 ocol : SV_Target)
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                #ifdef UNITY_FRAMEBUFFER_FETCH_AVAILABLE
                    fixed4 framebufferColor = ocol;
                    ocol = frac(sin(_Time.x * 45)) * ocol + col * _Color;
                #else
                    ocol = fixed4(1,0,0,1);
                #endif
            }
            ENDCG
        }
    }
}

Unity 2023.3.0a13, URP, tested on Meta Quest 3.

Hi!
There is currently no framebuffer fetch support enabled for Vulkan.
It looks like the recommended way to go forward with this is to use the RenderPass API.

Thanks - the issue we have is that any additional render passes are prohibitively expensive. An additional pass is 1-2ms of slowdown from memory bandwidth limitations on Quest 2 - as we only have 13.8ms total frametime, that’s up to 1/7th of our entire budget waiting on the system.

The only options we really have on this platform is framebuffer fetch, which is OpenGL-based (which would remove other features only available in Vulkan), or to use Vulkan Subpasses.

From this post, 11 months ago (Unity 2023.1.0a26, URP 15.0.3), Subpasses appear to not be working in Vulkan Multiview, as it only displays in the left eye:
Why doesn’t URP support using NativeRenderPass on the XR platform?

I guess I answered my own question - I’m out of luck with this right now. There is a Meta fork of UE4 that uses Vulkan subpasses on XR for color correction, so the hardware definitely works with this.

Any extra info you might have would be welcome!

Thanks

It may have been fixed since. If not, you can file a bug report :slight_smile:

They do. Our GDC talk on Rendering Customization and Performance in Unity 6 goes into detail about RenderGraph and how to benefit from pass merging, using framebuffer fetch, etc . You can find the recording freely available here.

You can find more info in [this]( https://discussions.unity.com/t/930355 page-7#post-9787632) thread as well.

@AljoshaD @aleksandrk If it’s possible then why isn’t it working here: How to Import color backbuffer to read on Meta Quest 3 + Vulkan
Is there a correct way to do this framebuffer fetching?
Or it can’t be written to a non-memoryless RT?

A memoryless resource could indeed not be converted from TextureHandle to RTHandle in the RG Execution phase. It’s fixed in 6.3.

In general, framebuffer input works with the backbuffer color (UniversalResourceData.backBufferColor), so you can read the color from the backbuffer. I think this works for Quest. For Vulkan in general, on general mobile, keep in mind that it works or not depending on the orientation of the phone (landscape mode or not). So it’s not feasible to make a robust implementation for Android for all devices that fetched the actual backbuffer.

Any updates on this? I have a custom SRP with vulkan using native render passes, but reading attachments is not a full replacement for this. You can only read from a previous attachment, and write to a new attachment. You can’t read and write to the same attachment. Large amounts of attachments slows down the binning phase quite a bit and you can only have 8 subpasses in a renderpass in total.

Framebuffer fetch in vulkan would make several effects signifcantly more acheivable/optional such as fog, water, decals, etc.

It’s not clear if this is a Unity or Vulkan limitation however. It does seem a bit odd that framebuffer fetch ‘just works’ in OpenGL but breaks entirely with Vulkan, you’d think they would have designed a replacement. (Renderpasses are not a direct replacement, as mentioned above)