NEW: Events now have unique IDs.

This commit is contained in:
Rene Damm rene@unity3d.com 2017-10-11 19:59:17 -07:00
Родитель 24d0a83c61
Коммит 94bc8cd87f
22 изменённых файлов: 450 добавлений и 109 удалений

Просмотреть файл

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using ISX;
using NUnit.Framework;
using UnityEngine;
using UnityEngineInternal.Input;
////TODO: make work in player (ATM we rely on the domain reload logic; probably want to include that in debug players, too)
@ -20,11 +20,16 @@ public class FunctionalTests
////REVIEW: We probably need to prevent device discoveries and events
//// that could happen on the native side from mucking with our
//// test. We can't completely disconnect from native, though,
//// as we need the event queue.
//// as we need the event queue. Could have a mode where we
//// don't send event discoveries and don't flush the background
//// queue.
// Put system in a blank state where it has all the templates but has
// none of the native devices.
InputSystem.Reset();
if (InputSystem.devices.Count > 0)
Assert.Fail("Input system should not have devices after reset");
}
[TearDown]
@ -771,11 +776,6 @@ public class FunctionalTests
Assert.That(device.leftStick.right.stateBlock.sizeInBits, Is.EqualTo(2 * 8));
}
struct CustomGamepadState
{
public short rightTrigger;
}
[Test]
[Category("State")]
public void State_CanStoreAxisAsShort()
@ -1422,23 +1422,6 @@ public class FunctionalTests
Assert.That(receivedCalls, Is.EqualTo(1));
}
[Test]
[Category("Events")]
public void Events_DeviceIdIsUnaffectedByHandledFlag()
{
// We internally use a bit in m_DeviceId to mark events as handled.
// Make sure we don't leak that fiddlery through the API.
var inputEvent = new InputEvent {deviceId = 5};
inputEvent.handled = true;
Assert.That(inputEvent.deviceId, Is.EqualTo(5));
inputEvent.deviceId = 6;
Assert.That(inputEvent.handled, Is.True);
}
[Test]
[Category("Events")]
public void Events_AreHandledInOrderOfIncreasingTime()
@ -1481,10 +1464,94 @@ public class FunctionalTests
Assert.That(receivedThirdTime, Is.EqualTo(kThirdTime).Within(0.00001));
}
[Test]
[Category("Events")]
public void Events_CanQueueAndReceiveEventsAgainstNonExistingDevices()
{
// Device IDs are looked up only *after* the system shows the event to us.
var receivedCalls = 0;
var receivedDeviceId = InputDevice.kInvalidDeviceId;
InputSystem.onEvent +=
eventPtr =>
{
++receivedCalls;
receivedDeviceId = eventPtr.deviceId;
};
var inputEvent = ConnectEvent.Create(4, 1.0);
InputSystem.QueueEvent(ref inputEvent);
InputSystem.Update();
Assert.That(receivedCalls, Is.EqualTo(1));
Assert.That(receivedDeviceId, Is.EqualTo(4));
}
[Test]
[Category("Events")]
public void Events_HandledFlagIsResetWhenEventIsQueued()
{
var receivedCalls = 0;
var wasHandled = true;
InputSystem.onEvent +=
eventPtr =>
{
++receivedCalls;
wasHandled = eventPtr.handled;
};
var inputEvent = ConnectEvent.Create(4, 1.0);
// This should go back to false when we inputEvent goes on the queue.
inputEvent.baseEvent.handled = true;
InputSystem.QueueEvent(ref inputEvent);
InputSystem.Update();
Assert.That(receivedCalls, Is.EqualTo(1));
Assert.That(wasHandled, Is.False);
}
[Test]
[Category("Events")]
public void Events_AlreadyHandledEventsAreIgnoredWhenProcessingEvents()
{
// Need a device with before render enabled so we can produce
// the effect of having already handled events in the event queue.
// If we use an invalid device, before render updates will simply
// ignore the event.
const string json = @"
{
""name"" : ""CustomGamepad"",
""extend"" : ""Gamepad"",
""beforeRender"" : ""Update""
}
";
InputSystem.RegisterTemplate(json);
var device = InputSystem.AddDevice("CustomGamepad");
InputSystem.onEvent +=
inputEvent =>
{
inputEvent.handled = true;
};
var event1 = ConnectEvent.Create(device.id, 1.0);
var event2 = ConnectEvent.Create(device.id, 2.0);
InputSystem.QueueEvent(ref event1);
// Before render update won't clear queue so after the update
// event1 is still in there.
InputSystem.Update(InputUpdateType.BeforeRender);
// Add new unhandled event.
InputSystem.QueueEvent(ref event2);
var receivedCalls = 0;
var receivedTime = 0.0;
@ -1494,20 +1561,11 @@ public class FunctionalTests
++receivedCalls;
receivedTime = inputEvent.time;
};
var device = InputSystem.AddDevice("Gamepad");
var unhandledEvent = ConnectEvent.Create(device.id, 1.0);
var handledEvent = ConnectEvent.Create(device.id, 2.0);
handledEvent.baseEvent.handled = true;
InputSystem.QueueEvent(ref unhandledEvent);
InputSystem.QueueEvent(ref handledEvent);
InputSystem.Update();
// On the second update, we should have seen only event2.
Assert.That(receivedCalls, Is.EqualTo(1));
Assert.That(receivedTime, Is.EqualTo(1.0).Within(0.00001));
Assert.That(receivedTime, Is.EqualTo(2.0).Within(0.00001));
}
[Test]
@ -1576,6 +1634,102 @@ public class FunctionalTests
}
}
[Test]
[Category("Events")]
public void Events_WhenTraceIsFull_WillStartOverwritingOldEvents()
{
var device = InputSystem.AddDevice("Gamepad");
var trace = new InputEventTrace(StateEvent.GetEventSizeWithPayload<GamepadState>() * 2) {deviceId = device.id};
trace.Enable();
try
{
var firstState = new GamepadState {rightTrigger = 0.35f};
var secondState = new GamepadState {leftTrigger = 0.75f};
var thirdState = new GamepadState {leftTrigger = 0.95f};
InputSystem.QueueStateEvent(device, firstState, 0.5);
InputSystem.QueueStateEvent(device, secondState, 1.5);
InputSystem.QueueStateEvent(device, thirdState, 2.5);
InputSystem.Update();
trace.Disable();
var events = trace.ToList();
Assert.That(events, Has.Count.EqualTo(2));
Assert.That(events, Has.Exactly(1).With.Property("time").EqualTo(1.5).Within(0.000001));
Assert.That(events, Has.Exactly(1).With.Property("time").EqualTo(2.5).Within(0.000001));
}
finally
{
trace.Dispose();
}
}
[Test]
[Category("Events")]
public void Events_GetUniqueIds()
{
var device = InputSystem.AddDevice("Gamepad");
InputSystem.QueueStateEvent(device, new GamepadState());
InputSystem.QueueStateEvent(device, new GamepadState());
var receivedCalls = 0;
var firstId = InputEvent.kInvalidId;
var secondId = InputEvent.kInvalidId;
InputSystem.onEvent +=
eventPtr =>
{
++receivedCalls;
if (receivedCalls == 1)
firstId = eventPtr.id;
else if (receivedCalls == 2)
secondId = eventPtr.id;
};
InputSystem.Update();
Assert.That(firstId, Is.Not.EqualTo(secondId));
}
[Test]
[Category("Events")]
public void Events_DoNotLeakIntoNextUpdate()
{
var device = InputSystem.AddDevice("Gamepad");
InputSystem.QueueStateEvent(device, new GamepadState(), 1.0);
InputSystem.QueueStateEvent(device, new GamepadState(), 2.0);
var receivedUpdateCalls = 0;
var receivedEventCount = 0;
NativeUpdateCallback onUpdate =
(updateType, eventCount, eventData) =>
{
++receivedUpdateCalls;
receivedEventCount += eventCount;
};
NativeInputSystem.onUpdate += onUpdate;
InputSystem.Update();
Assert.That(receivedUpdateCalls, Is.EqualTo(1));
Assert.That(receivedEventCount, Is.EqualTo(2));
receivedEventCount = 0;
receivedUpdateCalls = 0;
InputSystem.Update();
Assert.That(receivedEventCount, Is.Zero);
Assert.That(receivedUpdateCalls, Is.EqualTo(1));
}
[Test]
[Category("Actions")]
public void Actions_CanAddActionThatTargetsSingleControl()

Просмотреть файл

@ -0,0 +1,49 @@
using System.Reflection;
using ISX;
using NUnit.Framework;
using UnityEngine;
public class PerformanceTests
{
[SetUp]
public void Setup()
{
InputSystem.Save();
InputSystem.Reset();
}
[TearDown]
public void TearDown()
{
InputSystem.Restore();
}
// Performing a full state update on 10 devices should take less than 0.01 ms.
[Test]
[Category("Performance")]
public void CanUpdate10GamepadsInLessThanPointZeroOneMilliseconds()
{
const int kNumGamepads = 10;
var gamepads = new Gamepad[kNumGamepads];
for (var i = 0; i < kNumGamepads; ++i)
gamepads[i] = (Gamepad)InputSystem.AddDevice("Gamepad");
var startTime = Time.realtimeSinceStartup;
// Generate a full state update for each gamepad.
for (var i = 0; i < kNumGamepads; ++i)
InputSystem.QueueStateEvent(gamepads[i], new GamepadState());
// Now run the update.
InputSystem.Update();
var endTime = Time.realtimeSinceStartup;
var totalTime = endTime - startTime;
Assert.That(totalTime, Is.LessThan(0.01 / 1000.0));
Debug.Log($"{MethodBase.GetCurrentMethod().Name}: {totalTime*1000}ms");
}
////TODO: same test but with several actions listening on each gamepad
}

Просмотреть файл

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fbdee94cc663465f813d2081d675282d
timeCreated: 1507734516

Просмотреть файл

@ -3,6 +3,7 @@ using NUnit.Framework;
public class StressTests
{
[Test]
[Category("Stress")]
public void TODO_Create512GamepadsAndSend1024Events()
{
Assert.Fail();

Просмотреть файл

@ -62,6 +62,7 @@ namespace ISX
}
}
////REVIEW: this would technically allow a GetValue<TValue>() method
public InputControl lastSource => m_LastSource;
public bool enabled => m_Enabled;

Просмотреть файл

@ -24,6 +24,7 @@ namespace ISX
return value >= point;
}
////REVIEW: this may have to go into value itself; otherwise actions will trigger on the slightest value change
public bool isPressed => IsValueConsideredPressed(value);
public bool wasPressedThisFrame => IsValueConsideredPressed(value) && !IsValueConsideredPressed(previous);
public bool wasReleasedThisFrame => !IsValueConsideredPressed(value) && IsValueConsideredPressed(previous);

Просмотреть файл

@ -21,6 +21,11 @@ namespace ISX
public const string Pressure = "Pressure";
public const string Position = "Position";
public const string Orientation = "Orientation";
// Rotation around single, fixed axis.
// Example: twist on joystick or twist of pen (few pens support that).
public const string Twist = "Twist";
public const string Point = "Point";
public const string LowFreqMotor = "LowFreqMotor";

Просмотреть файл

@ -0,0 +1,6 @@
namespace ISX
{
public class Joystick
{
}
}

Просмотреть файл

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e14a578f61014fccab81ed0f1bc21948
timeCreated: 1507753901

Просмотреть файл

@ -0,0 +1,6 @@
namespace ISX
{
public class InputActionDebuggerWindow
{
}
}

Просмотреть файл

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7e9a52c3262d41cd9114cb475831dc7c
timeCreated: 1507756149

Просмотреть файл

@ -0,0 +1,6 @@
namespace ISX
{
public class InputActionInspector
{
}
}

Просмотреть файл

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 780f6a6e947c4acea6b872829d01b0e4
timeCreated: 1507756025

Просмотреть файл

@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
namespace ISX
{
// Input device got re-connected after a disconnect.
[StructLayout(LayoutKind.Explicit, Size = 20)]
[StructLayout(LayoutKind.Explicit, Size = InputEvent.kBaseEventSize)]
public struct ConnectEvent : IInputEventTypeInfo
{
public const int Type = 0x44434F4E;
@ -19,7 +19,7 @@ namespace ISX
public static ConnectEvent Create(int deviceId, double time)
{
var inputEvent = new ConnectEvent();
inputEvent.baseEvent = new InputEvent(Type, 20, deviceId, time);
inputEvent.baseEvent = new InputEvent(Type, InputEvent.kBaseEventSize, deviceId, time);
return inputEvent;
}
}

Просмотреть файл

@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
namespace ISX
{
// Input device got disconnected.
[StructLayout(LayoutKind.Explicit, Size = 20)]
[StructLayout(LayoutKind.Explicit, Size = InputEvent.kBaseEventSize)]
public struct DisconnectEvent : IInputEventTypeInfo
{
public const int Type = 0x44444953;
@ -19,7 +19,7 @@ namespace ISX
public static DisconnectEvent Create(int deviceId, double time)
{
var inputEvent = new DisconnectEvent();
inputEvent.baseEvent = new InputEvent(Type, 20, deviceId, time);
inputEvent.baseEvent = new InputEvent(Type, InputEvent.kBaseEventSize, deviceId, time);
return inputEvent;
}
}

Просмотреть файл

@ -4,31 +4,31 @@ namespace ISX
{
// A chunk of memory signaling a data transfer in the input system.
// This has to be layout compatible with native events.
[StructLayout(LayoutKind.Explicit, Size = InputEvent.kBaseEventSize)]
[StructLayout(LayoutKind.Explicit, Size = kBaseEventSize)]
public struct InputEvent : IInputEventTypeInfo
{
private const uint kHandledMask = 0x80000000;
private const uint kDeviceIdMask = 0x7FFFFFFF;
private const uint kIdMask = 0x7FFFFFFF;
public const int kBaseEventSize = 20;
public const int kInvalidId = 0;
[FieldOffset(0)]
private FourCC m_Type;
[FieldOffset(4)]
private int m_SizeInBytes;
[FieldOffset(8)]
private uint m_DeviceId;
[FieldOffset(12)]
private double m_Time;
[FieldOffset(0)] private FourCC m_Type;
[FieldOffset(4)] private ushort m_SizeInBytes;
[FieldOffset(6)] private ushort m_DeviceId;
[FieldOffset(8)] private uint m_EventId;
////REVIEW: does this really need to be a double? float would save us a 4 bytes
[FieldOffset(12)] private double m_Time;
public FourCC type => m_Type;
public int sizeInBytes => m_SizeInBytes;
public int eventId => (int)(m_EventId & kIdMask);
public int deviceId
{
// Need to mask out handled bit.
get { return (int)(m_DeviceId & kDeviceIdMask); }
set { m_DeviceId = (m_DeviceId & kHandledMask) | (uint)value; }
get { return m_DeviceId; }
set { m_DeviceId = (ushort)value; }
}
public double time
@ -40,9 +40,10 @@ namespace ISX
public InputEvent(FourCC type, int sizeInBytes, int deviceId, double time)
{
m_Type = type;
m_SizeInBytes = sizeInBytes;
m_DeviceId = (uint)deviceId;
m_SizeInBytes = (ushort)sizeInBytes;
m_DeviceId = (ushort)deviceId;
m_Time = time;
m_EventId = kInvalidId;
}
public FourCC GetTypeStatic()
@ -50,18 +51,20 @@ namespace ISX
return new FourCC(); // No valid type code; InputEvent is considered abstract.
}
// We internally use bits inside m_DeviceId as flags. Device IDs are
// linearly counted up by the native input system starting at 1 so we
// have plenty room in m_DeviceId.
// We internally use bits inside m_EventId as flags. IDs are linearly counted up by the
// native input system starting at 1 so we have plenty room.
// NOTE: The native system assigns IDs when events are queued so if our handled flag
// will implicitly get overwritten. Having events go back to unhandled state
// when they go on the queue makes sense in itself, though, so this is fine.
public bool handled
{
get { return (m_DeviceId & kHandledMask) == kHandledMask; }
set { m_DeviceId |= kHandledMask; }
get { return (m_EventId & kHandledMask) == kHandledMask; }
set { m_EventId |= kHandledMask; }
}
public override string ToString()
{
return $"type = {type}, device = {deviceId}, size = {sizeInBytes}, time = {time}";
return $"id={eventId} type={type} device={deviceId} size={sizeInBytes} time={time}";
}
}
}

Просмотреть файл

@ -35,6 +35,16 @@ namespace ISX
}
}
public int id
{
get
{
if (!valid)
return 0;
return m_EventPtr->eventId;
}
}
public FourCC type
{
get

Просмотреть файл

@ -93,12 +93,6 @@ namespace ISX
var nextEvent = current.data + current.sizeInBytes;
var endOfBuffer = m_EventBuffer + m_EventBufferSize;
Debug.Assert(nextEvent.ToInt64() < endOfBuffer.ToInt64());
// If we've run into our tail, there's no more events.
if (nextEvent.ToInt64() >= m_EventBufferTail.ToInt64())
return false;
// If we've reached blank space at the end of the buffer, wrap
// around to the beginning. In this scenario there must be an event
// at the beginning of the buffer; tail won't position itself at
@ -107,8 +101,10 @@ namespace ISX
((InputEvent*)nextEvent)->sizeInBytes == 0)
{
nextEvent = m_EventBuffer;
return true;
}
// If we've run into our tail, there's no more events.
else if (nextEvent.ToInt64() >= m_EventBufferTail.ToInt64())
return false;
// We're good. There's still space between us and our tail.
current = new InputEventPtr((InputEvent*)nextEvent);
@ -215,16 +211,28 @@ namespace ISX
newTail = m_EventBuffer + eventSize;
// Recheck whether we're overtaking head.
newTailOvertakesHead &= newTail.ToInt64() > m_EventBufferHead.ToInt64();
newTailOvertakesHead = newTail.ToInt64() > m_EventBufferHead.ToInt64();
}
// If the new tail runs into head, bump head as many times as we need to
// make room for the event. Head may itself wrap around here.
if (newTailOvertakesHead)
{
var ptr = new InputEventPtr((InputEvent*)m_EventBufferHead);
while (GetNextEvent(ref ptr))
m_EventBufferHead = ptr.data;
var newHead = (byte*)m_EventBufferHead;
var endOfBufferMinusOneEvent =
(byte*)m_EventBuffer + m_EventBufferSize - InputEvent.kBaseEventSize;
while (newHead < (byte*)newTail)
{
newHead += ((InputEvent*)newHead)->sizeInBytes;
if (newHead > endOfBufferMinusOneEvent)
{
newHead = (byte*)m_EventBuffer;
break;
}
}
m_EventBufferHead = new IntPtr(newHead);
}
buffer = m_EventBufferTail;

Просмотреть файл

@ -5,19 +5,17 @@ using UnityEngine;
namespace ISX
{
// Full state update for an input device.
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 25)]
// Variable-size event.
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = InputEvent.kBaseEventSize + 5)]
public unsafe struct StateEvent : IInputEventTypeInfo
{
public const int Type = 0x53544154;
[FieldOffset(0)]
public InputEvent baseEvent;
[FieldOffset(20)]
public FourCC stateFormat;
[FieldOffset(24)]
public fixed byte stateData[1]; // Variable-sized.
[FieldOffset(0)] public InputEvent baseEvent;
[FieldOffset(InputEvent.kBaseEventSize)] public FourCC stateFormat;
[FieldOffset(InputEvent.kBaseEventSize + 4)] public fixed byte stateData[1]; // Variable-sized.
public int stateSizeInBytes => baseEvent.sizeInBytes - 24;
public int stateSizeInBytes => baseEvent.sizeInBytes - (InputEvent.kBaseEventSize + 4);
public IntPtr state
{

Просмотреть файл

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Profiling;
using UnityEngineInternal.Input;
namespace ISX
@ -579,8 +580,8 @@ namespace ISX
if (ReferenceEquals(InputProcessor.s_Processors, m_Processors))
InputProcessor.s_Processors = null;
NativeInputSystem.onUpdate -= OnNativeUpdate;
NativeInputSystem.onDeviceDiscovered -= OnNativeDeviceDiscovered;
NativeInputSystem.onUpdate = null;
NativeInputSystem.onDeviceDiscovered = null;
}
// Revive after domain reload.
@ -591,8 +592,8 @@ namespace ISX
InputTemplate.s_BaseTemplateTable = m_BaseTemplateTable;
InputProcessor.s_Processors = m_Processors;
NativeInputSystem.onUpdate += OnNativeUpdate;
NativeInputSystem.onDeviceDiscovered += OnNativeDeviceDiscovered;
NativeInputSystem.onUpdate = OnNativeUpdate;
NativeInputSystem.onDeviceDiscovered = OnNativeDeviceDiscovered;
}
// Bundles a template name and a device description.
@ -797,6 +798,13 @@ namespace ISX
// to the global state buffers so the user won't ever know that updates happen in the background.
private unsafe void OnNativeUpdate(NativeInputUpdateType updateType, int eventCount, IntPtr eventData)
{
#if ENABLE_PROFILER
Profiler.BeginSample("InputUpdate");
try
{
#endif
////REVIEW: this will become obsolete when we actually turn off unneeded updates in native
// We *always* have to process events into the current state even if the given update isn't enabled.
// This is because the current state is for all updates and reflects the most up-to-date device states.
@ -805,10 +813,13 @@ namespace ISX
if (eventCount <= 0)
return;
var isBeforeRenderUpdate = false;
if (updateType == NativeInputUpdateType.Dynamic)
++m_CurrentDynamicUpdateCount;
else if (updateType == NativeInputUpdateType.Fixed)
++m_CurrentFixedUpdateCount;
else if (updateType == NativeInputUpdateType.BeforeRender)
isBeforeRenderUpdate = true;
// Before render updates work in a special way. For them, we only want specific devices (and
// sometimes even just specific controls on those devices) to be updated. What native will do is
@ -820,37 +831,91 @@ namespace ISX
// be used to, for example, *only* update tracking on a device that also contains buttons -- which
// should not get updated in berfore render).
var firstEventPtr = (InputEvent*)eventData;
var remainingEventCount = eventCount;
// Handle events.
var firstEvent = (InputEvent*)eventData;
for (var i = 0; i < eventCount; ++i)
while (remainingEventCount > 0)
{
// Bump firstEvent up to the next unhandled event.
while (eventCount > 0 && firstEvent->handled)
InputDevice device = null;
InputEvent* currentEventPtr;
double currentEventTime;
////REVIEW: The whole event sorting/filtering logic here is too convoluted. Unfortunately,
//// neither the sorting by time nor the filtering of before-render events is
//// super trivial. Hope there is a much simpler and also more performant way to do
//// this. I'm pretty sure that the cost of the sorting especially can easily
//// overshadow the cost of event handling itself.
#if ENABLE_PROFILER
Profiler.BeginSample("SortInputEvents");
try
{
firstEvent = (InputEvent*)((byte*)firstEvent + firstEvent->sizeInBytes);
--eventCount;
#endif
// Bump firstEvent up to the next unhandled event (in before-render updates
// the event needs to be *both* unhandled *and* for a device with before
// render updates enabled).
while (remainingEventCount > 0)
{
if (isBeforeRenderUpdate)
{
if (!firstEventPtr->handled)
{
device = TryGetDeviceById(firstEventPtr->deviceId);
if (device != null && device.updateBeforeRender)
break;
}
}
else if (!firstEventPtr->handled)
break;
firstEventPtr = (InputEvent*)((byte*)firstEventPtr + firstEventPtr->sizeInBytes);
--remainingEventCount;
}
if (eventCount == 0)
if (remainingEventCount == 0)
break;
////REVIEW: can we do this faster?
// Find next oldest unhandled event.
var currentEventPtr = firstEvent;
currentEventPtr = firstEventPtr;
var oldestEventPtr = currentEventPtr;
var oldestEventTime = oldestEventPtr->time;
for (var n = 1; n < eventCount; ++n)
for (var n = 1; n < remainingEventCount; ++n)
{
var nextEventPtr = (InputEvent*)((byte*)currentEventPtr + currentEventPtr->sizeInBytes);
if (!nextEventPtr->handled && nextEventPtr->time < oldestEventTime)
if (isBeforeRenderUpdate)
{
if (!nextEventPtr->handled && nextEventPtr->time < oldestEventTime)
{
var nextEventDevice = TryGetDeviceById(nextEventPtr->deviceId);
if (nextEventDevice != null && nextEventDevice.updateBeforeRender)
{
oldestEventPtr = nextEventPtr;
oldestEventTime = nextEventPtr->time;
device = nextEventDevice;
}
}
}
else if (!nextEventPtr->handled && nextEventPtr->time < oldestEventTime)
{
oldestEventPtr = nextEventPtr;
oldestEventTime = oldestEventPtr->time;
oldestEventTime = nextEventPtr->time;
}
currentEventPtr = nextEventPtr;
}
currentEventPtr = oldestEventPtr;
var currentEventTime = oldestEventTime;
currentEventTime = oldestEventTime;
#if ENABLE_PROFILER
}
finally
{
Profiler.EndSample();
}
#endif
// Give listeners a shot at the event.
if (m_EventReceivedEvent != null)
@ -860,26 +925,22 @@ namespace ISX
continue;
}
// Grab device for event.
var device = TryGetDeviceById(currentEventPtr->deviceId);
// Grab device for event. In before-render updates, we already had to
// check the device.
if (!isBeforeRenderUpdate)
device = TryGetDeviceById(currentEventPtr->deviceId);
if (device == null)
{
// No device found matching event. Consider it handled.
currentEventPtr->handled = true;
continue;
}
// Process.
var currentEventType = currentEventPtr->type;
switch (currentEventType)
{
case StateEvent.Type:
// In before render updates, only devices that explicitly enable
// before render updates will see their state updated. Events shown
// to us in before render updates will re-surface again on the next
// normal update so we can safely skip those events.
if (updateType == NativeInputUpdateType.BeforeRender && !device.updateBeforeRender)
////FIXME: have to make sure next iteration doesn't come up with the same
//// event again; current code produces an infinite loop
continue;
var stateEventPtr = (StateEvent*)currentEventPtr;
var stateType = stateEventPtr->stateFormat;
var stateBlock = device.m_StateBlock;
@ -977,13 +1038,30 @@ namespace ISX
}
// Mark as processed by setting time to negative.
oldestEventPtr->handled = true;
currentEventPtr->handled = true;
// If the event we handled was the first one at our current buffer position and
// have still more events to go, bump our buffer position by one.
if (currentEventPtr == firstEventPtr && remainingEventCount >= 1)
{
firstEventPtr = (InputEvent*)((byte*)currentEventPtr + currentEventPtr->sizeInBytes);
--remainingEventCount;
}
// Device received event so make it current.
device.MakeCurrent();
}
////TODO: fire event that allows code to update state *from* state we just updated
#if ENABLE_PROFILER
}
finally
{
Profiler.EndSample();
}
#endif
}
// If anyone is listening for state changes on the given device, run state change detections

Просмотреть файл

@ -35,6 +35,9 @@ GraphicsSettings:
- {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 16001, guid: 0000000000000000f000000000000000, type: 0}
m_PreloadedShaders: []
m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000,
type: 0}

Просмотреть файл

@ -89,7 +89,7 @@ PlayerSettings:
visibleInBackground: 1
allowFullscreenSwitch: 1
graphicsJobMode: 0
fullscreenMode: -1
fullscreenMode: 1
xboxSpeechDB: 0
xboxEnableHeadOrientation: 0
xboxEnableGuest: 0