From 08b13460ae1afcf73c3d51c29a7418357680c75050fec30f0ed28e1bbe1eadc7 Mon Sep 17 00:00:00 2001 From: copecone Date: Fri, 9 Oct 2026 14:39:30 +0900 Subject: [PATCH] Optimize `FrameReader` by Caching Color Conversion Kernel --- Util/FrameReader.cs | 64 +++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/Util/FrameReader.cs b/Util/FrameReader.cs index 07f6e78..7514182 100644 --- a/Util/FrameReader.cs +++ b/Util/FrameReader.cs @@ -26,12 +26,34 @@ namespace ADOFAIRenderer.Util private readonly object _poolLock = new(); private bool _isInitialized; private volatile bool _isDisposed; - - private readonly AVPixelFormat _targetFormat; + + private readonly ComputeShader? _computeShader; + private readonly int _kernelIndex = -1; + private readonly bool _useGPUConversion; + private readonly AVPixelFormat _expectedFormat; public FrameReader(AVPixelFormat targetFormat) { - _targetFormat = targetFormat; + _computeShader = ModAssets.ColorConversionShader; + if (_computeShader) + { + var kernelName = targetFormat switch + { + AVPixelFormat.AV_PIX_FMT_NV12 => "CSMain_NV12", + AVPixelFormat.AV_PIX_FMT_YUV420P => "CSMain_YUV420P", + _ => null + }; + + if (kernelName != null) + { + try { _kernelIndex = _computeShader.FindKernel(kernelName); } + catch { _kernelIndex = -1; } + } + } + + _useGPUConversion = _kernelIndex >= 0; + _expectedFormat = _useGPUConversion ? targetFormat : AVPixelFormat.AV_PIX_FMT_RGBA; + InitializePool(); } @@ -71,42 +93,22 @@ namespace ADOFAIRenderer.Util state.IsInFlight = true; } - // Check if GPU color conversion is available - var expectedFmt = AVPixelFormat.AV_PIX_FMT_RGBA; - - var kernelIndex = -1; - if (ModAssets.ColorConversionShader) - { - var kernalName = _targetFormat switch - { - 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); + state.Setup(currentFrame, bufferSize, _useGPUConversion, _expectedFormat, texture.width, texture.height); - if (useGPUConversion && state.GPUBuffer != null && ModAssets.ColorConversionShader) + if (_useGPUConversion && state.GPUBuffer != null && _computeShader) { - 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); + _computeShader.SetTexture(_kernelIndex, SourceTexture, texture); + _computeShader.SetBuffer(_kernelIndex, DestinationBuffer, state.GPUBuffer); + _computeShader.SetInt(Width, texture.width); + _computeShader.SetInt(Height, texture.height); - var threadGroupsX = expectedFmt == AVPixelFormat.AV_PIX_FMT_NV12 + var threadGroupsX = _expectedFormat == 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); + _computeShader.Dispatch(_kernelIndex, threadGroupsX, threadGroupsY, 1); AsyncGPUReadback.RequestIntoNativeArray( ref state.NativeBuffer, state.GPUBuffer, state.CachedCallback