SHA256
Move Memory Copy Handling from Main Thread to Render Thread
This commit is contained in:
1 parent
459b2f3b0e
commit
036216c006
2 files changed
+68
-25
No files matched your search
+50
-11
@@ -79,8 +79,16 @@ namespace ADOFAIRenderer.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal struct CapturedFrame
|
||||||
|
{
|
||||||
|
public IntPtr NativePointer;
|
||||||
|
public int Length;
|
||||||
|
public byte[]? ManagedBuffer; // Non-null if it's a managed buffer (e.g. black frame)
|
||||||
|
public ReadbackRequestState? ReadbackState; // Associated state to recycle
|
||||||
|
}
|
||||||
|
|
||||||
// Thread and Queue State
|
// Thread and Queue State
|
||||||
public SortedList<long, byte[]> ImageQueue = new SortedList<long, byte[]>();
|
internal SortedList<long, CapturedFrame> ImageQueue = new SortedList<long, CapturedFrame>();
|
||||||
public Thread? RenderThread;
|
public Thread? RenderThread;
|
||||||
public long passCount;
|
public long passCount;
|
||||||
public bool endRequested;
|
public bool endRequested;
|
||||||
@@ -202,7 +210,11 @@ namespace ADOFAIRenderer.Core
|
|||||||
|
|
||||||
lock (ImageQueue)
|
lock (ImageQueue)
|
||||||
{
|
{
|
||||||
ImageQueue[videoFrameIndex] = blackFrame;
|
ImageQueue[videoFrameIndex] = new CapturedFrame
|
||||||
|
{
|
||||||
|
ManagedBuffer = blackFrame,
|
||||||
|
Length = byteSize
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +428,8 @@ namespace ADOFAIRenderer.Core
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
byte[]? buffer = null;
|
CapturedFrame frame = default;
|
||||||
|
bool hasFrame = false;
|
||||||
lock (ImageQueue)
|
lock (ImageQueue)
|
||||||
{
|
{
|
||||||
if (ImageQueue.Count > 0)
|
if (ImageQueue.Count > 0)
|
||||||
@@ -430,20 +443,42 @@ namespace ADOFAIRenderer.Core
|
|||||||
|
|
||||||
if (firstKey == passCount)
|
if (firstKey == passCount)
|
||||||
{
|
{
|
||||||
buffer = ImageQueue[firstKey];
|
frame = ImageQueue[firstKey];
|
||||||
ImageQueue.RemoveAt(0);
|
ImageQueue.RemoveAt(0);
|
||||||
passCount++;
|
passCount++;
|
||||||
|
hasFrame = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer != null)
|
if (hasFrame)
|
||||||
{
|
{
|
||||||
if (buffer.Length > 0)
|
if (frame.ManagedBuffer != null)
|
||||||
{
|
{
|
||||||
var bufferSize = Configuration.RenderWidth * Configuration.RenderHeight * 4;
|
if (frame.ManagedBuffer.Length > 0)
|
||||||
videoFFmpeg.SendDataFromBuffer(buffer, bufferSize);
|
{
|
||||||
|
videoFFmpeg.SendDataFromBuffer(frame.ManagedBuffer, frame.Length);
|
||||||
|
ArrayPool<byte>.Shared.Return(frame.ManagedBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (frame.NativePointer != IntPtr.Zero && frame.Length > 0)
|
||||||
|
{
|
||||||
|
var buffer = FFmpegProcess.RentRawBytes(frame.Length);
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* destPtr = buffer)
|
||||||
|
{
|
||||||
|
Buffer.MemoryCopy((void*)frame.NativePointer, destPtr, buffer.Length, frame.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
videoFFmpeg.SendDataFromBuffer(buffer, frame.Length);
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
|
||||||
|
if (frame.ReadbackState != null)
|
||||||
|
{
|
||||||
|
_frameReader?.RecycleState(frame.ReadbackState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -514,11 +549,15 @@ namespace ADOFAIRenderer.Core
|
|||||||
// 1. 메모리 누수 방지: 큐에 렌트된 임시 프레임 버퍼 풀 반환 및 클리어
|
// 1. 메모리 누수 방지: 큐에 렌트된 임시 프레임 버퍼 풀 반환 및 클리어
|
||||||
lock (ImageQueue)
|
lock (ImageQueue)
|
||||||
{
|
{
|
||||||
foreach (var kvp in ImageQueue)
|
foreach (var kvp in ImageQueue.Values)
|
||||||
{
|
{
|
||||||
if (kvp.Value != null && kvp.Value.Length > 0)
|
if (kvp.ManagedBuffer != null && kvp.ManagedBuffer.Length > 0)
|
||||||
{
|
{
|
||||||
ArrayPool<byte>.Shared.Return(kvp.Value);
|
ArrayPool<byte>.Shared.Return(kvp.ManagedBuffer);
|
||||||
|
}
|
||||||
|
if (kvp.ReadbackState != null)
|
||||||
|
{
|
||||||
|
_frameReader?.RecycleState(kvp.ReadbackState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImageQueue.Clear();
|
ImageQueue.Clear();
|
||||||
|
|||||||
+18
-14
@@ -91,28 +91,32 @@ namespace ADOFAIRenderer.Util
|
|||||||
var byteSize = state.NativeBuffer.Length;
|
var byteSize = state.NativeBuffer.Length;
|
||||||
var blackFrame = ArrayPool<byte>.Shared.Rent(byteSize);
|
var blackFrame = ArrayPool<byte>.Shared.Rent(byteSize);
|
||||||
Array.Clear(blackFrame, 0, byteSize);
|
Array.Clear(blackFrame, 0, byteSize);
|
||||||
PushToQueue(frame, blackFrame);
|
|
||||||
|
var capFrame = new RenderManager.CapturedFrame
|
||||||
|
{
|
||||||
|
ManagedBuffer = blackFrame,
|
||||||
|
Length = byteSize
|
||||||
|
};
|
||||||
|
PushToQueue(frame, capFrame);
|
||||||
|
RecycleState(state);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
var ptr = state.NativeBuffer.GetUnsafeReadOnlyPtr();
|
var ptr = (IntPtr)state.NativeBuffer.GetUnsafeReadOnlyPtr();
|
||||||
var rawBytes = FFmpegProcess.RentRawBytes(state.NativeBuffer.Length);
|
var capFrame = new RenderManager.CapturedFrame
|
||||||
|
|
||||||
fixed (byte* destPtr = rawBytes)
|
|
||||||
{
|
{
|
||||||
Buffer.MemoryCopy(ptr, destPtr, rawBytes.Length, state.NativeBuffer.Length);
|
NativePointer = ptr,
|
||||||
}
|
Length = state.NativeBuffer.Length,
|
||||||
|
ReadbackState = state
|
||||||
PushToQueue(frame, rawBytes);
|
};
|
||||||
|
PushToQueue(frame, capFrame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RecycleState(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RecycleState(ReadbackRequestState state)
|
internal void RecycleState(ReadbackRequestState state)
|
||||||
{
|
{
|
||||||
lock (_poolLock)
|
lock (_poolLock)
|
||||||
{
|
{
|
||||||
@@ -127,12 +131,12 @@ namespace ADOFAIRenderer.Util
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PushToQueue(long frame, byte[] rawBytes)
|
private static void PushToQueue(long frame, RenderManager.CapturedFrame capturedFrame)
|
||||||
{
|
{
|
||||||
if (!RenderManager.Instance) return;
|
if (!RenderManager.Instance) return;
|
||||||
lock (RenderManager.Instance.ImageQueue)
|
lock (RenderManager.Instance.ImageQueue)
|
||||||
{
|
{
|
||||||
RenderManager.Instance.ImageQueue[frame] = rawBytes;
|
RenderManager.Instance.ImageQueue[frame] = capturedFrame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user