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}