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