- 프레임버퍼 페치는비디오 메모리 대신 GPU의 온칩 메모리에서 프레임버퍼에 액세스할 수 있는 렌더 패스를 허용하는 프로세스
- 모바일 기기에서 타일 기반 지연 렌더링(TBDR)을 사용하는 모바일 기기에서 렌더링 속도가 향상
https://docs.unity3d.com/6000.0/Documentation/Manual/urp/render-graph-framebuffer-fetch.html
FBF( Frame Buffer Fetch)
SetInputAttachment
- support API
- Vulkan
- Metal
Input
FRAMEBUFFER_INPUT_X_HALF
FRAMEBUFFER_INPUT_X_FLOAT
FRAMEBUFFER_INPUT_X_INT
FRAMEBUFFER_INPUT_X_UINT
Load
LOAD_FRAMEBUFFER_INPUT(idx)
LOAD_FRAMEBUFFER_INPUT_MS(idx,sampleIdx) // 멀티샘플링(MSAA)이 활성화된 텍스처를 처리하기 위해 사용됨.
builder.SetInputAttachment(sourceTextureHandle, 0, AccessFlags.Read);
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
TextureHandle source = resourceData.activeColorTexture;
TextureDesc destinationDesc = renderGraph.GetTextureDesc(source);
destinationDesc.name = "FBFetchDestTexture";
destinationDesc.clearBuffer = false;
if (destinationDesc.msaaSamples == MSAASamples.None || RenderGraphUtils.CanAddCopyPassMSAA())
{
bool isUseMSAA = destinationDesc.msaaSamples != MSAASamples.None;
TextureHandle fbFetchDestination = renderGraph.CreateTexture(destinationDesc);
FBFetchPass(renderGraph, frameData, srcHandle: source, dstHandle: fbFetchDestination, isUseMSAA);
renderGraph.AddCopyPass(fbFetchDestination, source, passName: "Copy Back FF Destination (also using FBF)");
}
else
{
Debug.Log("Can't add the FBF pass and the copy pass due to MSAA");
}
}
private void FBFetchPass(RenderGraph renderGraph, ContextContainer frameData, TextureHandle srcHandle, TextureHandle dstHandle, bool isUseMSAA)
{
string passName = "FrameBufferFetchPass";
using (IRasterRenderGraphBuilder builder = renderGraph.AddRasterRenderPass(passName, out PassData passData))
{
passData.material = m_FBFetchMaterial;
passData.isUseMSAA = isUseMSAA;
builder.SetInputAttachment(tex: srcHandle, index: 0, AccessFlags.Read);
builder.SetRenderAttachment(tex: dstHandle, index: 0); // Output
builder.AllowPassCulling(false);
builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecuteFBFetchPass(data, context));
}
}
static void ExecuteFBFetchPass(PassData data, RasterGraphContext context)
{
context.cmd.DrawProcedural(Matrix4x4.identity, data.material, data.useMSAA ? 1 : 0, MeshTopology.Triangles, 3, 1, null);
}
Shader "FrameBufferFetch"
{
SubShader
{
Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"}
ZWrite Off Cull Off
Pass
{
Name "FrameBufferFetch"
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#pragma vertex Vert
#pragma fragment Frag
FRAMEBUFFER_INPUT_HALF(0);
// Out frag function takes as input a struct that contains the screen space coordinate we are going to use to sample our texture. It also writes to SV_Target0, this has to match the index set in the UseTextureFragment(sourceTexture, 0, …) we defined in our render pass script.
float4 Frag(Varyings input) : SV_Target0
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); // for XR platform
float2 uv = input.texcoord.xy;
half4 color = LOAD_FRAMEBUFFER_INPUT(0, input.positionCS.xy);
return half4(0,0,1,1) * color;
}
ENDHLSL
}
Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"}
ZWrite Off Cull Off
Pass
{
Name "FrameBufferFetchMS"
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#pragma vertex Vert
#pragma fragment Frag
#pragma target 4.5
#pragma require msaatex
FRAMEBUFFER_INPUT_HALF_MS(0);
// Out frag function takes as input a struct that contains the screen space coordinate we are going to use to sample our texture. It also writes to SV_Target0, this has to match the index set in the UseTextureFragment(sourceTexture, 0, …) we defined in our render pass script.
float4 Frag(Varyings input, uint sampleID : SV_SampleIndex) : SV_Target0
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); // for XR platform
float2 uv = input.texcoord.xy;
half4 color = LOAD_FRAMEBUFFER_INPUT_MS(0, sampleID, input.positionCS.xy);
// Modify the sampled color
return half4(0,0,1,1) * color;
}
ENDHLSL
}
}
}