A game about forced loneliness, made by TACStudios
1using Unity.Collections;
2using Unity.Collections.LowLevel.Unsafe;
3
4namespace UnityEngine.InputSystem.LowLevel
5{
6 /// <summary>
7 /// The input event stream is a combination of the input event buffer passed from native code and an
8 /// append buffer that is owned by the managed side. Events queued during update are added to the
9 /// append buffer. To calling code, the two buffers look like a single coherent stream of events.
10 /// Calling Advance will first step through the events from the native side, followed by any events
11 /// that have been appended.
12 /// </summary>
13 internal unsafe struct InputEventStream
14 {
15 public bool isOpen => m_IsOpen;
16
17 public int remainingEventCount => m_RemainingNativeEventCount + m_RemainingAppendEventCount;
18
19 /// <summary>
20 /// How many events were left in the native buffer during reading.
21 /// </summary>
22 public int numEventsRetainedInBuffer => m_NumEventsRetainedInBuffer;
23
24 public InputEvent* currentEventPtr => m_RemainingNativeEventCount > 0
25 ? m_CurrentNativeEventReadPtr
26 : (m_RemainingAppendEventCount > 0 ? m_CurrentAppendEventReadPtr : null);
27
28 public uint numBytesRetainedInBuffer =>
29 (uint)((byte*)m_CurrentNativeEventWritePtr -
30 (byte*)NativeArrayUnsafeUtility
31 .GetUnsafeBufferPointerWithoutChecks(m_NativeBuffer.data));
32
33 public InputEventStream(ref InputEventBuffer eventBuffer, int maxAppendedEvents)
34 {
35 m_CurrentNativeEventWritePtr = m_CurrentNativeEventReadPtr =
36 (InputEvent*)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(eventBuffer.data);
37
38 m_NativeBuffer = eventBuffer;
39 m_RemainingNativeEventCount = m_NativeBuffer.eventCount;
40 m_NumEventsRetainedInBuffer = 0;
41
42 m_CurrentAppendEventReadPtr = m_CurrentAppendEventWritePtr = default;
43 m_AppendBuffer = default;
44 m_RemainingAppendEventCount = 0;
45 m_MaxAppendedEvents = maxAppendedEvents;
46
47 m_IsOpen = true;
48 }
49
50 public void Close(ref InputEventBuffer eventBuffer)
51 {
52 // If we have retained events, update event count and buffer size. If not, just reset.
53 if (m_NumEventsRetainedInBuffer > 0)
54 {
55 var bufferPtr = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(m_NativeBuffer.data);
56 Debug.Assert((byte*)m_CurrentNativeEventWritePtr > (byte*)bufferPtr);
57 var newBufferSize = (byte*)m_CurrentNativeEventWritePtr - (byte*)bufferPtr;
58 m_NativeBuffer = new InputEventBuffer((InputEvent*)bufferPtr, m_NumEventsRetainedInBuffer, (int)newBufferSize,
59 (int)m_NativeBuffer.capacityInBytes);
60 }
61 else
62 {
63 m_NativeBuffer.Reset();
64 }
65
66 if (m_AppendBuffer.data.IsCreated)
67 m_AppendBuffer.Dispose();
68
69 eventBuffer = m_NativeBuffer;
70 m_IsOpen = false;
71 }
72
73 public void CleanUpAfterException()
74 {
75 if (!isOpen)
76 return;
77
78 m_NativeBuffer.Reset();
79
80 if (m_AppendBuffer.data.IsCreated)
81 m_AppendBuffer.Dispose();
82
83 m_IsOpen = false;
84 }
85
86 public void Write(InputEvent* eventPtr)
87 {
88 if (m_AppendBuffer.eventCount >= m_MaxAppendedEvents)
89 {
90 Debug.LogError($"Maximum number of queued events exceeded. Set the '{nameof(InputSettings.maxQueuedEventsPerUpdate)}' " +
91 $"setting to a higher value if you need to queue more events than this. " +
92 $"Current limit is '{m_MaxAppendedEvents}'.");
93 return;
94 }
95
96 var wasAlreadyCreated = m_AppendBuffer.data.IsCreated;
97 var oldBufferPtr = (byte*)m_AppendBuffer.bufferPtr.data;
98
99 m_AppendBuffer.AppendEvent(eventPtr, allocator: Allocator.Temp);
100
101 if (!wasAlreadyCreated)
102 {
103 m_CurrentAppendEventWritePtr = m_CurrentAppendEventReadPtr =
104 (InputEvent*)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(m_AppendBuffer.data);
105 }
106 else
107 {
108 // AppendEvent can reallocate the buffer if it needs more space, so make sure the read and write pointers
109 // point to the equivalent places in the new buffer.
110 var newBufferPtr = (byte*)m_AppendBuffer.bufferPtr.data;
111 if (oldBufferPtr != newBufferPtr)
112 {
113 var currentWriteOffset = (byte*)m_CurrentAppendEventWritePtr - oldBufferPtr;
114 var currentReadOffset = (byte*)m_CurrentAppendEventReadPtr - oldBufferPtr;
115 m_CurrentAppendEventWritePtr = (InputEvent*)(newBufferPtr + currentWriteOffset);
116 m_CurrentAppendEventReadPtr = (InputEvent*)(newBufferPtr + currentReadOffset);
117 }
118 }
119
120 m_RemainingAppendEventCount++;
121 }
122
123 public InputEvent* Advance(bool leaveEventInBuffer)
124 {
125 if (m_RemainingNativeEventCount > 0)
126 {
127 m_NativeBuffer.AdvanceToNextEvent(ref m_CurrentNativeEventReadPtr, ref m_CurrentNativeEventWritePtr,
128 ref m_NumEventsRetainedInBuffer, ref m_RemainingNativeEventCount, leaveEventInBuffer);
129 }
130 else if (m_RemainingAppendEventCount > 0)
131 {
132 var numEventRetained = 0;
133 m_AppendBuffer.AdvanceToNextEvent(ref m_CurrentAppendEventReadPtr, ref m_CurrentAppendEventWritePtr,
134 ref numEventRetained, ref m_RemainingAppendEventCount, false);
135 }
136
137 return currentEventPtr;
138 }
139
140 /// <summary>
141 /// Peeks next event in the stream
142 /// </summary>
143 public InputEvent* Peek()
144 {
145 // Advance will go to next event in m_NativeBuffer
146 if (m_RemainingNativeEventCount > 1)
147 return InputEvent.GetNextInMemory(m_CurrentNativeEventReadPtr);
148
149 // Advance will decrement m_RemainingNativeEventCount to 0
150 // and currentEventPtr will point to m_CurrentAppendEventReadPtr if any
151 if (m_RemainingNativeEventCount == 1)
152 return m_RemainingAppendEventCount > 0 ? m_CurrentAppendEventReadPtr : null;
153
154 // Advance will go to next event in m_AppendBuffer
155 if (m_RemainingAppendEventCount > 1)
156 return InputEvent.GetNextInMemory(m_CurrentAppendEventReadPtr);
157
158 // No next event
159 return null;
160 }
161
162 private InputEventBuffer m_NativeBuffer;
163 private InputEvent* m_CurrentNativeEventReadPtr;
164 private InputEvent* m_CurrentNativeEventWritePtr;
165 private int m_RemainingNativeEventCount;
166 private readonly int m_MaxAppendedEvents;
167
168 // During Update, new events that are queued will be added to the append buffer
169 private InputEventBuffer m_AppendBuffer;
170 private InputEvent* m_CurrentAppendEventReadPtr;
171 private InputEvent* m_CurrentAppendEventWritePtr;
172 private int m_RemainingAppendEventCount;
173
174 // When timeslicing events or in before-render updates, we may be leaving events in the buffer
175 // for later processing. We do this by compacting the event buffer and moving events down such
176 // that the events we leave in the buffer form one contiguous chunk of memory at the beginning
177 // of the buffer.
178 private int m_NumEventsRetainedInBuffer;
179 private bool m_IsOpen;
180 }
181}