Document Render Core And API

This commit is contained in:
copecone committed 2026-10-15 16:17:13 +09:00
1 parent 354c42fdd9
commit 8deb64fd4d
22 files changed
+1241 -27

No files matched your search

+54
View File
@@ -6,16 +6,58 @@ using UnityEngine;
namespace ADOFAIRenderer.Core;
/// <summary>
/// Runs the frame hooks (session and global, see RenderSession) on a captured frame before it is read back.
/// Owns two RenderTextures (ping and pong) with the size and format of the source frame; each hook pass reads the
/// current frame and writes the other buffer (see FrameHookContext). One instance per render, created in
/// RenderManager.SetupPlay and disposed when the render ends. Main thread only.
/// </summary>
internal class FrameHookPipeline : IDisposable
{
/// <summary>First ping-pong buffer. Created by EnsureBuffers, released by ReleaseBuffers.</summary>
private RenderTexture? _pingRT;
/// <summary>Second ping-pong buffer. Created by EnsureBuffers, released by ReleaseBuffers.</summary>
private RenderTexture? _pongRT;
/// <summary>
/// Buffer returned as the output of the previous Process call (ping or pong), or null when the previous frame was
/// not modified by any hook. Its readback may still be in flight, so the next frame starts writing the other buffer.
/// </summary>
private RenderTexture? _lastOutputRT;
/// <summary>Context object passed to the hooks; reset and reused for every frame (no allocation per frame).</summary>
private FrameHookContext? _reusableContext;
/// <summary>Width of the current buffers in pixels (0 when no buffers exist).</summary>
private int _width;
/// <summary>Height of the current buffers in pixels (0 when no buffers exist).</summary>
private int _height;
/// <summary>Format of the source texture the current buffers were created for.</summary>
private RenderTextureFormat _format;
/// <summary>
/// Runs <paramref name="hooks"/> in order on <paramref name="sourceTexture"/> and returns the resulting texture.
/// An exception thrown by a hook is logged and the remaining hooks still run.
/// RenderTexture.active is restored after the hooks.
/// </summary>
/// <param name="sourceTexture">Captured game frame. Hooks do not write into it (they write the ping-pong buffers).</param>
/// <param name="frameIndex">Video frame index (0-based) of this frame.</param>
/// <param name="renderFrameIndex">
/// Render frame index (0-based, RenderManager.frameCountForVideo): counts every game frame since capture started,
/// including game frames that were not captured because they fall in an already captured video frame.
/// </param>
/// <param name="videoTime">Time of this video frame in seconds from the start of the video.</param>
/// <param name="renderFps">Render frame rate (game frames per second).</param>
/// <param name="videoFps">Effective video frame rate (min(VideoFPS, RenderFPS)).</param>
/// <param name="hooks">Hooks to run, in order. Session hooks come before global hooks.</param>
/// <returns>
/// <paramref name="sourceTexture"/> when there are no hooks, the source is not created, the buffers could not be
/// created, or no hook modified the frame; otherwise the texture holding the final frame (a ping-pong buffer, or a
/// texture a hook passed to FrameHookContext.ReplaceCurrent).
/// </returns>
public RenderTexture? Process(
RenderTexture sourceTexture,
long frameIndex,
@@ -81,6 +123,8 @@ internal class FrameHookPipeline : IDisposable
}
}
// Current is the source when nothing was modified. A texture set by ReplaceCurrent is stored in
// _lastOutputRT too; it then matches neither buffer and the next frame starts with ping.
var result = _reusableContext.Current;
_lastOutputRT = _reusableContext.HasModified ? result : null;
return result;
@@ -91,6 +135,12 @@ internal class FrameHookPipeline : IDisposable
}
}
/// <summary>
/// Creates the ping and pong buffers when they do not exist, were released, or the source size or format changed.
/// The buffers copy the source descriptor without depth, MSAA and mipmaps, and enable random write (UAV) when the
/// GPU supports compute shaders and random write for that format, so compute shaders can write them.
/// When creating them from the descriptor throws, ARGB32 buffers of the same size are created.
/// </summary>
private void EnsureBuffers(RenderTexture sourceTexture)
{
var width = sourceTexture.width;
@@ -160,6 +210,9 @@ internal class FrameHookPipeline : IDisposable
}
}
/// <summary>
/// Releases and destroys both buffers and drops the reusable context. The next Process call creates them again.
/// </summary>
public void ReleaseBuffers()
{
if (_pingRT)
@@ -182,6 +235,7 @@ internal class FrameHookPipeline : IDisposable
_reusableContext = null;
}
/// <summary>Same as <see cref="ReleaseBuffers"/>. Main thread (Object.Destroy is used).</summary>
public void Dispose()
{
ReleaseBuffers();