Hi @AMoulin , thank you for your reply!
I’ve investigated the AddBlitPass() and ImportTexture() method and the other high-level APIs.
After a while I’ve succeeded to do a copy with both eyes. But it’s a very messy and dirty code. I’ve taken the FinalBlitPass as an example to achieve that. I noticed also that even if I put the renderPassEvent as renderPassEvent = RenderPassEvent.AfterRendering + 30 it will never occur after the FinalBlit. This is fine for the copy I guess, but since my camera is only needed for the copy, is there a way to not do the FinalBlit + XRDepthCopy? Because it’s useless in my copy case, right?
Here’s a look of my render graph. Is it how it’s supposed to look? (The RT I am copying data is called XRCamera)
Also, I’ve battled a lot with the RenderingUtils.ReAllocateHandleIfNeeded, calling it break the RenderTexture (The one I am doing the copy, XRCamera), looks like that re-allocating a texture, even if it’s because of its name, breaks the Blitter.BlitTexture.
Here’s the code to acheive the copy, inspired from FinalBlitPass. Is it a good approach?
public class XRCopyPass : ScriptableRenderPass
{
// From FinalBlitPass
private class PassData
{
internal TextureHandle source;
internal TextureHandle destination;
internal int sourceID;
internal bool requireSrgbConversion;
internal bool enableAlphaOutput;
internal BlitMaterialData blitMaterialData;
internal UniversalCameraData cameraData;
}
// From FinalBlitPass
private struct BlitMaterialData
{
public Material material;
public int nearestSamplerPass;
public int bilinearSamplerPass;
}
// From FinalBlitPass
private static class BlitPassNames
{
public const string NearestSampler = "NearestDebugDraw";
public const string BilinearSampler = "BilinearDebugDraw";
}
private readonly string _passName;
private readonly int _sourceTexId = Shader.PropertyToID("_SourceTex");
private readonly int _id = 0;
private BlitMaterialData _blitMaterialData;
private readonly RenderTexture _destinationRenderTexture;
private TextureHandle _destination;
private RTHandle _destinationHandle = null;
public XRCopyPass(Camera camera, int index, RenderTexture destinationRenderTexture = null)
{
requiresIntermediateTexture = true;
renderPassEvent = RenderPassEvent.AfterRendering + 30; // The max range is + 50 !
_id = index;
_passName = string.Format("XRCopyPass_{1}", passName, _id);
_destinationRenderTexture = destinationRenderTexture;
GraphicsSettings.TryGetRenderPipelineSettings<UniversalRenderPipelineRuntimeShaders>(out var shadersResources);
Material blitMaterial = CoreUtils.CreateEngineMaterial(shadersResources.coreBlitPS);
_blitMaterialData.material = blitMaterial;
_blitMaterialData.nearestSamplerPass = blitMaterial?.FindPass(BlitPassNames.NearestSampler) ?? -1;
_blitMaterialData.bilinearSamplerPass = blitMaterial?.FindPass(BlitPassNames.BilinearSampler) ?? -1;
UniversalAdditionalCameraData universalAdditionalCameraData = camera.GetComponent<UniversalAdditionalCameraData>();
universalAdditionalCameraData.scriptableRenderer.EnqueuePass(this);
}
public void Render(RenderGraph renderGraph, ContextContainer frameData)
{
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
if (cameraData.xr.enabled)
{
using (IRasterRenderGraphBuilder builder = renderGraph.AddRasterRenderPass(_passName, out PassData passData))
{
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
if (_destinationHandle == null)
{
_destinationHandle = RTHandles.Alloc(_destinationRenderTexture);
}
// When the _destinationRenderTexture contains depthStencilFormat, we need to remove otherwise the ImportTexture will fail
// But this doesn't seem to work, the output texture is empty
/*RenderTextureDescriptor descriptor = new RenderTextureDescriptor(
_destinationRenderTexture.width,
_destinationRenderTexture.height,
_destinationRenderTexture.format,
_destinationRenderTexture.mipmapCount)
{
stencilFormat = GraphicsFormat.None,
depthStencilFormat = GraphicsFormat.None,
};
RenderingUtils.ReAllocateHandleIfNeeded(
ref _destinationHandle, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp,
_destinationRenderTexture.anisoLevel, _destinationRenderTexture.mipMapBias, _destinationRenderTexture.name);*/
_destination = renderGraph.ImportTexture(_destinationHandle);
InitPassData(cameraData, ref passData);
passData.sourceID = _sourceTexId;
passData.source = resourceData.cameraColor;
builder.UseTexture(passData.source, AccessFlags.Read);
passData.destination = _destination;
builder.SetRenderAttachment(_destination, 0, AccessFlags.Write); // Write or WriteAll?
// This is a screen-space pass, make sure foveated rendering is disabled for non-uniform renders
bool passSupportsFoveation = !XRSystem.foveatedRenderingCaps.HasFlag(FoveatedRenderingCaps.NonUniformRaster);
builder.EnableFoveatedRasterization(cameraData.xr.supportsFoveatedRendering && passSupportsFoveation);
// Removing this line will cause the whole editor to...display crap. Unity needs to be restarted after
builder.AllowGlobalStateModification(true);
builder.AllowPassCulling(false);
builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
{
// Important to have good colors
context.cmd.SetKeyword(ShaderGlobalKeywords.LinearToSRGBConversion, data.requireSrgbConversion);
data.blitMaterialData.material.SetTexture(data.sourceID, data.source);
ExecutePass(context.cmd, data, data.source, data.destination, data.cameraData);
});
}
}
}
private void InitPassData(UniversalCameraData cameraData, ref PassData passData)
{
passData.cameraData = cameraData;
// This is forced to true because we are in B8G8R8A8_UNorm, not sRGB and linear (cameraData.requireSrgbConversion is not accessible)
passData.requireSrgbConversion = true;// cameraData.requireSrgbConversion;
passData.enableAlphaOutput = cameraData.isAlphaOutputEnabled;
passData.blitMaterialData = _blitMaterialData;
}
private static void ExecutePass(RasterCommandBuffer cmd, PassData data, RTHandle source, RTHandle destination, UniversalCameraData cameraData)
{
Vector4 scaleBias = GetFinalBlitScaleBias(source, destination, cameraData);
CoreUtils.SetKeyword(data.blitMaterialData.material, ShaderKeywordStrings._ENABLE_ALPHA_OUTPUT, data.enableAlphaOutput);
if (source.rt != null)
{
int shaderPassIndex = source.rt.filterMode == FilterMode.Bilinear ? data.blitMaterialData.bilinearSamplerPass : data.blitMaterialData.nearestSamplerPass;
Blitter.BlitTexture(cmd, source, scaleBias, data.blitMaterialData.material, shaderPassIndex);
}
}
// From RenderingUtils
private static Vector4 GetFinalBlitScaleBias(RTHandle source, RTHandle destination, UniversalCameraData cameraData)
{
Vector2 viewportScale = source.useScaling ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) : Vector2.one;
var yflip = cameraData.IsRenderTargetProjectionMatrixFlipped(destination);
Vector4 scaleBias = !yflip ? new Vector4(viewportScale.x, -viewportScale.y, 0, viewportScale.y) : new Vector4(viewportScale.x, viewportScale.y, 0, 0);
return scaleBias;
}
public void Dispose()
{
_destinationHandle?.Release();
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
Render(renderGraph, frameData);
}
}
