SHA256
Optimize Frame Readback and Encoding Pipeline
This commit is contained in:
3 files changed
+58
-111
No files matched your search
+40
-58
@@ -71,72 +71,55 @@ namespace ADOFAIRenderer.Util
|
||||
state.IsInFlight = true;
|
||||
}
|
||||
|
||||
// Check if GPU color conversion is enabled
|
||||
bool useGPUConversion = ModAssets.ColorConversionShader;
|
||||
AVPixelFormat expectedFmt = AVPixelFormat.AV_PIX_FMT_RGBA;
|
||||
|
||||
if (useGPUConversion)
|
||||
// Check if GPU color conversion is available
|
||||
var expectedFmt = AVPixelFormat.AV_PIX_FMT_RGBA;
|
||||
|
||||
var kernelIndex = -1;
|
||||
if (ModAssets.ColorConversionShader)
|
||||
{
|
||||
expectedFmt = _targetFormat;
|
||||
// Compute Shader only supports NV12 and YUV420P; fallback to CPU for other formats
|
||||
if (expectedFmt != AVPixelFormat.AV_PIX_FMT_NV12 && expectedFmt != AVPixelFormat.AV_PIX_FMT_YUV420P)
|
||||
var kernalName = _targetFormat switch
|
||||
{
|
||||
useGPUConversion = false;
|
||||
}
|
||||
AVPixelFormat.AV_PIX_FMT_NV12 => "CSMain_NV12",
|
||||
AVPixelFormat.AV_PIX_FMT_YUV420P => "CSMain_YUV420P",
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (kernalName != null)
|
||||
kernelIndex = ModAssets.ColorConversionShader.FindKernel(kernalName);
|
||||
}
|
||||
|
||||
var useGPUConversion = kernelIndex >= 0;
|
||||
if (useGPUConversion) expectedFmt = _targetFormat;
|
||||
|
||||
var bufferSize = texture.width * texture.height * 4; // RGBA = 4 channel
|
||||
state.Setup(currentFrame, bufferSize, useGPUConversion, expectedFmt, texture.width, texture.height);
|
||||
|
||||
if (useGPUConversion && state.GPUBuffer != null && ModAssets.ColorConversionShader)
|
||||
{
|
||||
int kernelIndex = -1;
|
||||
if (expectedFmt == AVPixelFormat.AV_PIX_FMT_NV12)
|
||||
{
|
||||
kernelIndex = ModAssets.ColorConversionShader.FindKernel("CSMain_NV12");
|
||||
}
|
||||
else if (expectedFmt == AVPixelFormat.AV_PIX_FMT_YUV420P)
|
||||
{
|
||||
kernelIndex = ModAssets.ColorConversionShader.FindKernel("CSMain_YUV420P");
|
||||
}
|
||||
ModAssets.ColorConversionShader.SetTexture(kernelIndex, SourceTexture, texture);
|
||||
ModAssets.ColorConversionShader.SetBuffer(kernelIndex, DestinationBuffer, state.GPUBuffer);
|
||||
ModAssets.ColorConversionShader.SetInt(Width, texture.width);
|
||||
ModAssets.ColorConversionShader.SetInt(Height, texture.height);
|
||||
|
||||
if (kernelIndex >= 0)
|
||||
{
|
||||
ModAssets.ColorConversionShader.SetTexture(kernelIndex, SourceTexture, texture);
|
||||
ModAssets.ColorConversionShader.SetBuffer(kernelIndex, DestinationBuffer, state.GPUBuffer);
|
||||
ModAssets.ColorConversionShader.SetInt(Width, texture.width);
|
||||
ModAssets.ColorConversionShader.SetInt(Height, texture.height);
|
||||
var threadGroupsX = expectedFmt == AVPixelFormat.AV_PIX_FMT_NV12
|
||||
? (texture.width + 31) / 32
|
||||
: (texture.width + 63) / 64;
|
||||
var threadGroupsY = (texture.height + 15) / 16;
|
||||
|
||||
var threadGroupsX = expectedFmt == AVPixelFormat.AV_PIX_FMT_NV12
|
||||
? (texture.width + 31) / 32
|
||||
: (texture.width + 63) / 64;
|
||||
var threadGroupsY = (texture.height + 15) / 16;
|
||||
ModAssets.ColorConversionShader.Dispatch(kernelIndex, threadGroupsX, threadGroupsY, 1);
|
||||
|
||||
ModAssets.ColorConversionShader.Dispatch(kernelIndex, threadGroupsX, threadGroupsY, 1);
|
||||
|
||||
AsyncGPUReadback.Request(
|
||||
state.GPUBuffer,
|
||||
state.CachedCallback
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If kernel is not found, fallback to standard RGBA texture readback
|
||||
AsyncGPUReadback.RequestIntoNativeArray(
|
||||
ref state.NativeBuffer,
|
||||
texture,
|
||||
0,
|
||||
state.CachedCallback
|
||||
);
|
||||
}
|
||||
AsyncGPUReadback.RequestIntoNativeArray(
|
||||
ref state.NativeBuffer, state.GPUBuffer, state.CachedCallback
|
||||
);
|
||||
/*AsyncGPUReadback.Request(
|
||||
state.GPUBuffer,
|
||||
state.CachedCallback
|
||||
);*/
|
||||
}
|
||||
else
|
||||
{
|
||||
AsyncGPUReadback.RequestIntoNativeArray(
|
||||
ref state.NativeBuffer,
|
||||
texture,
|
||||
0,
|
||||
state.CachedCallback
|
||||
ref state.NativeBuffer, texture, 0, state.CachedCallback
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -169,16 +152,14 @@ namespace ADOFAIRenderer.Util
|
||||
}
|
||||
Melon<RenderMod>.Logger.Warning($"[OOM Prevent] GPU Readback failed for frame {frame}. Queue deadlock prevented by sending a black frame.");
|
||||
|
||||
var byteSize = state.IsGPUConversion
|
||||
? state.Width * state.Height * 3 / 2
|
||||
: state.Width * state.Height * 4;
|
||||
var byteSize = state.Width * state.Height * 3 / 2;
|
||||
var blackFrame = ArrayPool<byte>.Shared.Rent(byteSize);
|
||||
Array.Clear(blackFrame, 0, byteSize);
|
||||
|
||||
var capFrame = new RenderManager.CapturedFrame
|
||||
{
|
||||
ManagedBuffer = blackFrame,
|
||||
Length = byteSize
|
||||
ManagedBuffer = blackFrame, Length = byteSize,
|
||||
IsColorConverted = true
|
||||
};
|
||||
PushToQueue(frame, capFrame);
|
||||
RecycleState(state);
|
||||
@@ -187,19 +168,20 @@ namespace ADOFAIRenderer.Util
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
/*
|
||||
if (state.IsGPUConversion)
|
||||
{
|
||||
var data = request.GetData<byte>();
|
||||
// Copy async request buffer data to persistent NativeBuffer memory
|
||||
NativeArray<byte>.Copy(data, state.NativeBuffer, data.Length);
|
||||
}
|
||||
*/
|
||||
|
||||
var ptr = (IntPtr)state.NativeBuffer.GetUnsafeReadOnlyPtr();
|
||||
var capFrame = new RenderManager.CapturedFrame
|
||||
{
|
||||
NativePointer = ptr,
|
||||
Length = state.NativeBuffer.Length,
|
||||
ReadbackState = state
|
||||
NativePointer = ptr, Length = state.NativeBuffer.Length,
|
||||
ReadbackState = state, IsColorConverted = state.IsGPUConversion
|
||||
};
|
||||
PushToQueue(frame, capFrame);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user