Skip to content

Instantly share code, notes, and snippets.

@rngtm
Last active June 26, 2023 22:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rngtm/c313ca0ac3987a60aa108ec55e9cce70 to your computer and use it in GitHub Desktop.
Save rngtm/c313ca0ac3987a60aa108ec55e9cce70 to your computer and use it in GitHub Desktop.
URP 10.7.0でのフルスクリーンエフェクトでのRenderBufferのロード・ストア最適化の検証
Shader "Hidden/CustomImageEffect"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
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;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
half4 frag (v2f i) : SV_Target
{
float2 uv = i.uv;
uv.x += sin(uv.y * 64.0) * 0.01;
return tex2D(_MainTex, uv);
}
ENDCG
}
}
}
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.Universal;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class CustomImageEffectFeature : ScriptableRendererFeature
{
class CustomRenderPass : ScriptableRenderPass
{
private bool m_IsOptimizeLoadStore;
private Material m_Material;
private int m_RepeatCount;
public void Setup(RenderPassEvent passEvent, Material material, int repeatCount = 1, bool optimizeLoadStore = false)
{
renderPassEvent = passEvent;
m_Material = material;
m_IsOptimizeLoadStore = optimizeLoadStore;
m_RepeatCount = repeatCount;
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
base.Configure(cmd, cameraTextureDescriptor);
// ポストエフェクト用の一時テクスチャを作成 (RenderTextureはGPUメモリ上に乗っている)
var desc = cameraTextureDescriptor;
cameraTextureDescriptor.depthBufferBits = 0;
cameraTextureDescriptor.stencilFormat = GraphicsFormat.None;
cmd.GetTemporaryRT(ShaderPropertyId.TempTex1, desc);
cmd.GetTemporaryRT(ShaderPropertyId.TempTex2, desc);
}
// Here you can implement the rendering logic.
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var cmd = CommandBufferPool.Get($"CustomImageEffect (Repeat: {m_RepeatCount}");
RenderTargetIdentifier cameraColorTarget = renderingData.cameraData.renderer.cameraColorTarget;
int buffer1 = ShaderPropertyId.TempTex1;
int buffer2 = ShaderPropertyId.TempTex2;
cmd.Blit(cameraColorTarget, buffer1);
RenderBufferLoadAction colorLoadAction;
RenderBufferStoreAction colorStoreAction;
if (PostEffectSettings.IsOptimizeLoadStoreColor)
{
// カラーバッファのロードを行わない
colorLoadAction = RenderBufferLoadAction.DontCare;
colorStoreAction = RenderBufferStoreAction.Store;
}
else
{
// カラーバッファのロード・ストアが行われる
colorLoadAction = RenderBufferLoadAction.Load;
colorStoreAction = RenderBufferStoreAction.Store;
}
RenderBufferLoadAction depthLoadAction;
RenderBufferStoreAction depthStoreAction;
if (PostEffectSettings.IsOptimizeLoadStoreDepth)
{
// デプスのロード・ストアを行わない
depthLoadAction = RenderBufferLoadAction.DontCare;
depthStoreAction = RenderBufferStoreAction.DontCare;
}
else
{
// デプスのロード・ストアが行われる (不要)
depthLoadAction = RenderBufferLoadAction.Load;
depthStoreAction = RenderBufferStoreAction.Store;
}
for (int i = 0; i < m_RepeatCount; i++)
{
if (m_IsOptimizeLoadStore)
{
cmd.SetRenderTarget(buffer2,
colorLoadAction,
colorStoreAction,
depthLoadAction,
depthStoreAction);
}
else
{
cmd.SetRenderTarget(buffer2);
}
cmd.Blit(buffer1, buffer2, m_Material);
if (i != m_RepeatCount - 1)
{
// swap
(buffer1, buffer2) = (buffer2, buffer1);
}
}
if (m_IsOptimizeLoadStore)
{
cmd.SetRenderTarget(buffer2,
colorLoadAction,
colorStoreAction,
depthLoadAction,
depthStoreAction);
}
cmd.Blit(buffer2, cameraColorTarget);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
// Cleanup any allocated resources that were created during the execution of this render pass.
public override void OnCameraCleanup(CommandBuffer cmd)
{
cmd.ReleaseTemporaryRT(ShaderPropertyId.TempTex1);
cmd.ReleaseTemporaryRT(ShaderPropertyId.TempTex2);
}
}
private CustomRenderPass m_ScriptablePass;
private Material m_Material;
[SerializeField] private Settings settings = new Settings();
[System.Serializable]
private class Settings
{
public RenderPassEvent RenderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
}
/// <inheritdoc/>
public override void Create()
{
m_ScriptablePass = new CustomRenderPass();
m_ScriptablePass.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
if (m_Material == null)
{
m_Material = CoreUtils.CreateEngineMaterial("Hidden/CustomImageEffect");
}
}
// Here you can inject one or multiple render passes in the renderer.
// This method is called when setting up the renderer once per-camera.
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (PostEffectSettings.RepeatCount > 0)
{
m_ScriptablePass.Setup(settings.RenderPassEvent, m_Material, PostEffectSettings.RepeatCount, PostEffectSettings.IsOptimizeLoadStore);
renderer.EnqueuePass(m_ScriptablePass);
}
}
}
public static class PostEffectSettings
{
public static int RepeatCount = 30; // Blitの実行回数
public static bool IsOptimizeLoadStore = true; // RenderBufferのロード・ストアの最適化
public static bool IsOptimizeLoadStoreColor = true; // RenderBuffer(カラーバッファ)のロード・ストアの最適化
public static bool IsOptimizeLoadStoreDepth = true; // RenderBuffer(デプスバッファ)のロード・ストアの最適化
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment