8internal sealed class RenderFrameMailbox : IDisposable
34 internal sealed class Slot
36 internal RenderFrameSnapshot? Frame {
get;
set; }
37 internal State Ownership;
42 private readonly
object _gate =
new();
43 private readonly Slot[] _slots = [
new(),
new(),
new()];
44 private Slot? _published;
46 private long _publishedCount;
47 private long _droppedCount;
49 internal (
long Published,
long Dropped,
int InUse) Counters
54 return (_publishedCount, _droppedCount, _slots.Count(s => s.Ownership != State.Free));
58 internal Slot? TryBeginBuild()
62 if (_closed)
return null;
63 if (_slots.Any(s => s.Ownership == State.Building))
64 throw new InvalidOperationException(
"Only one snapshot producer is supported.");
65 var slot = _slots.FirstOrDefault(s => s.Ownership == State.Free);
66 if (slot is
null)
return null;
67 slot.Ownership = State.Building;
73 internal void Publish(Slot slot, RenderFrameSnapshot frame)
78 Require(slot, State.Building);
82 slot.Ownership = State.Releasing;
88 if (retired is not
null)
90 retired.Ownership = State.Releasing;
93 slot.Ownership = State.Published;
98 if (retired is not
null) Recycle(retired);
101 internal void AbortBuild(Slot slot)
105 Require(slot, State.Building);
106 slot.Ownership = State.Free;
110 internal Slot? TryAcquire()
114 if (_closed || _published is
null)
return null;
115 if (_slots.Any(s => s.Ownership == State.Rendering))
116 throw new InvalidOperationException(
"Only one snapshot consumer is supported.");
117 var slot = _published;
119 slot.Ownership = State.Rendering;
124 internal void Release(Slot slot)
128 Require(slot, State.Rendering);
129 slot.Ownership = State.Releasing;
134 private void Require(Slot slot, State state)
136 if (!Array.Exists(_slots, candidate => ReferenceEquals(candidate, slot)) || slot.Ownership != state)
137 throw new InvalidOperationException(
"Snapshot slot is not owned by this operation.");
140 private void Recycle(Slot slot)
142 try { slot.Frame?.Dispose(); }
148 slot.Ownership = State.Free;
156 public void Dispose()
163 retired = _published;
165 if (retired is not
null) retired.Ownership = State.Releasing;
168 if (retired is not
null) Recycle(retired);