Files
Xune/UIX.RenderApi.Skia/Microsoft/Iris/Render/Protocol/MessagingSession.cs
T

412 lines
16 KiB
C#
Raw Normal View History

2021-07-11 22:59:29 -05:00
// Decompiled with JetBrains decompiler
// Type: Microsoft.Iris.Render.Protocol.MessagingSession
// Assembly: UIX.RenderApi, Version=4.8.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217
// MVID: D47658B8-A8EA-43D6-8837-ECE823BFFFC1
// Assembly location: C:\Program Files\Zune\UIX.RenderApi.dll
using Microsoft.Iris.Render.Common;
using Microsoft.Iris.Render.Internal;
using System;
using System.Threading;
namespace Microsoft.Iris.Render.Protocol
{
2021-07-11 23:04:40 -05:00
internal sealed class MessagingSession : RenderObject
2021-07-11 22:59:29 -05:00
{
2021-07-11 23:04:40 -05:00
private static Map<Thread, MessagingSession> s_sessions = new Map<Thread, MessagingSession>();
private readonly ContextID m_localContextId;
private bool m_isConnected;
private int m_pingRequestCount;
private IRenderHost m_renderHost;
private Thread m_owningThread;
private Vector m_ports;
private Vector m_activeTrackers;
private RenderPort m_portRendering;
private RenderPort m_portWindowing;
private bool m_isBatchingMessages;
private BatchCallback m_batchFillCallback;
private BatchCallback m_batchBeginCallbacks;
private BatchCallback m_batchEndCallbacks;
private BatchCallback m_batchDeliveryCallbacks;
private bool m_fBatchFlushRequested;
private DeferredInvokeItem m_batchFlushInvokeItem;
private EngineApi.MessageBufferEventHandler m_messageBufferHandler;
private TimeoutHandler m_externalTimeoutHandler;
private EngineApi.TimeoutEventHandler m_internalTimeoutHandler;
2021-07-11 22:59:29 -05:00
2021-07-11 23:04:40 -05:00
internal MessagingSession(IRenderHost renderHost, RenderToken token)
2021-07-11 23:07:04 -05:00
: this(renderHost, token, null, 0U)
2021-07-11 22:59:29 -05:00
{
}
2021-07-11 23:41:18 -05:00
internal unsafe MessagingSession(
2021-07-11 23:04:40 -05:00
IRenderHost renderHost,
RenderToken token,
TimeoutHandler handlerTimeout,
uint nTimeoutSec)
2021-07-11 22:59:29 -05:00
{
2021-07-11 23:04:40 -05:00
Debug2.Validate(renderHost != null, typeof(ArgumentNullException), nameof(renderHost));
Debug2.Validate(token != null, typeof(ArgumentNullException), nameof(token));
Debug2.Validate(token.LocalContextId != ContextID.NULL, typeof(ArgumentNullException), "token.LocalContextId");
Debug2.Validate(token.EngineInfo is IrisEngineInfo, typeof(ArgumentException), "token.EngineInfo");
this.m_pingRequestCount = 0;
this.m_renderHost = renderHost;
this.m_ports = new Vector(2);
this.m_localContextId = token.LocalContextId;
2021-07-11 23:07:04 -05:00
this.m_batchFlushInvokeItem = new DeferredInvokeItem(null, new DeferredHandler(this.ProcessDeferredFlushBatch), null);
2021-07-11 23:04:40 -05:00
this.m_batchFillCallback = new BatchCallback(this.OnBatchFirstMessage);
this.InitializeLocalMessaging(this.m_localContextId, new EngineApi.MessageBufferEventHandler(this.OnIncomingMessageBuffer), nTimeoutSec, handlerTimeout);
this.m_portRendering = this.CreatePort((token.EngineInfo as IrisEngineInfo).ConnectionInfo, token.DestinationContextId, token.RenderGroupId);
2021-07-11 23:07:04 -05:00
this.m_portWindowing = null;
2021-07-11 23:04:40 -05:00
this.m_activeTrackers = new Vector();
}
protected override void Dispose(bool fInDispose)
{
try
{
if (fInDispose)
{
if (this.IsConnected)
this.Disconnect();
this.DisposeRemainingDataBufferTrackers();
foreach (RenderPort port in this.m_ports)
port.Dispose();
this.m_ports.Clear();
this.ShutdownLocalMessaging();
}
2021-07-11 23:07:04 -05:00
this.m_activeTrackers = null;
this.m_portWindowing = null;
this.m_portRendering = null;
this.m_ports = null;
this.m_renderHost = null;
2021-07-11 23:04:40 -05:00
}
finally
{
base.Dispose(fInDispose);
}
}
internal static MessagingSession Current
{
get
{
2021-07-11 23:07:04 -05:00
lock (s_sessions)
return s_sessions.ContainsKey(Thread.CurrentThread) ? s_sessions[Thread.CurrentThread] : null;
2021-07-11 23:04:40 -05:00
}
}
internal Thread OwningThread => this.m_owningThread;
internal bool IsConnected => this.m_isConnected;
internal ContextID LocalContext => this.m_localContextId;
internal RenderPort RenderingPort => this.m_portRendering;
internal RenderPort WindowingPort => this.m_portWindowing == null ? this.m_portRendering : this.m_portWindowing;
private void InitializeLocalMessaging(
ContextID localContextId,
EngineApi.MessageBufferEventHandler messageHandler,
uint timeoutInSeconds,
TimeoutHandler timeoutHandler)
{
this.m_messageBufferHandler = messageHandler;
this.m_externalTimeoutHandler = timeoutHandler;
this.m_internalTimeoutHandler = new EngineApi.TimeoutEventHandler(this.OnTimedOut);
EngineApi.InitArgs args = new EngineApi.InitArgs(MessageCookieLayout.Default, localContextId, messageHandler);
if (timeoutInSeconds > 0U && timeoutHandler != null)
{
args.pfnTimeout = this.m_internalTimeoutHandler;
args.nTimeOutSec = timeoutInSeconds;
}
EngineApi.IFC(EngineApi.SpInit(ref args));
2021-07-11 23:07:04 -05:00
lock (s_sessions)
2021-07-11 23:04:40 -05:00
{
this.m_owningThread = Thread.CurrentThread;
2021-07-11 23:07:04 -05:00
s_sessions[this.m_owningThread] = this;
2021-07-11 23:04:40 -05:00
}
}
private void ShutdownLocalMessaging()
{
2021-07-11 23:07:04 -05:00
lock (s_sessions)
2021-07-11 23:04:40 -05:00
{
2021-07-11 23:07:04 -05:00
s_sessions.Remove(this.m_owningThread);
this.m_owningThread = null;
2021-07-11 23:04:40 -05:00
}
EngineApi.IFC(EngineApi.SpUninit());
2021-07-11 23:07:04 -05:00
this.m_messageBufferHandler = null;
this.m_externalTimeoutHandler = null;
this.m_internalTimeoutHandler = null;
2021-07-11 23:04:40 -05:00
}
internal static void DoEvents(uint nTimeoutInMsecs)
{
EngineApi.SpWaitMessage(nTimeoutInMsecs, IntPtr.Zero);
EngineApi.SpPeekMessage(out Win32Api.MSG _, HWND.NULL, 0U, 0U, 1U, out EngineApi.WorkResult _);
}
private RenderPort CreatePort(
ConnectionInfo connectionInfo,
ContextID destinationContextId,
RENDERGROUP grpObjects)
{
foreach (RenderPort port in this.m_ports)
Debug2.Validate(port.RemoteContext != destinationContextId, typeof(ArgumentException), "There already is a RenderPort allocated for this destination context");
bool foreignByteOrder = false;
IChannel channel;
switch (connectionInfo)
{
case LocalConnectionInfo _:
2021-07-11 23:07:04 -05:00
channel = new LocalChannel((LocalConnectionInfo)connectionInfo);
2021-07-11 23:04:40 -05:00
break;
case RemoteConnectionInfo _:
RemoteConnectionInfo connectionInfo1 = (RemoteConnectionInfo)connectionInfo;
2021-07-11 23:07:04 -05:00
channel = new RemoteChannel(connectionInfo1);
2021-07-11 23:04:40 -05:00
foreignByteOrder = connectionInfo1.SwapByteOrder;
break;
default:
2021-07-11 23:07:04 -05:00
return null;
2021-07-11 23:04:40 -05:00
}
RenderPort renderPort = new RenderPort(this, channel, destinationContextId, grpObjects, MessageCookieLayout.Default, foreignByteOrder);
if (this.m_isConnected)
renderPort.Connect();
2021-07-11 23:07:04 -05:00
this.m_ports.Add(renderPort);
2021-07-11 23:04:40 -05:00
return renderPort;
}
internal DataBufferTracker CreateDataBufferTracker(object objUser) => new DataBufferTracker(objUser);
internal void ReturnDataBufferTracker(DataBufferTracker tracker)
{
if (tracker.Count != 0)
{
tracker.TrackerEmpty += new EventHandler(this.OnDataBufferTrackerEmpty);
2021-07-11 23:07:04 -05:00
this.m_activeTrackers.Add(tracker);
2021-07-11 23:04:40 -05:00
}
else
tracker.Dispose();
}
private void OnDataBufferTrackerEmpty(object objSender, EventArgs args)
{
DataBufferTracker dataBufferTracker = (DataBufferTracker)objSender;
2021-07-11 23:07:04 -05:00
this.m_activeTrackers.Remove(dataBufferTracker);
2021-07-11 23:04:40 -05:00
dataBufferTracker.TrackerEmpty -= new EventHandler(this.OnDataBufferTrackerEmpty);
dataBufferTracker.Dispose();
}
private void DisposeRemainingDataBufferTrackers()
{
if (this.m_activeTrackers.Count <= 0)
return;
foreach (DataBufferTracker activeTracker in this.m_activeTrackers)
activeTracker.Dispose();
this.m_activeTrackers.Clear();
}
internal void Connect()
{
Debug2.Throw(!this.m_isConnected, "MessagingSession is already connected");
foreach (RenderPort port in this.m_ports)
port.Connect();
this.Synchronize();
this.StartNewBatch();
this.m_isConnected = true;
}
internal void Disconnect()
{
Debug2.Throw(this.m_isConnected, "MessagingSession is not connected");
this.FlushCurrentBatch(true);
this.Synchronize();
foreach (RenderPort port in this.m_ports)
port.DisposeObjectMaps();
foreach (RenderPort port in this.m_ports)
port.Dispose();
this.m_ports.Clear();
this.m_isConnected = false;
}
internal void Synchronize()
{
foreach (RenderPort port in this.m_ports)
{
port.PingReply += new EventHandler(this.OnPingReply);
++this.m_pingRequestCount;
port.PingConnection();
}
if (this.m_isBatchingMessages)
this.FlushBatch();
while (this.m_pingRequestCount > 0)
2021-07-11 23:07:04 -05:00
DoEvents(uint.MaxValue);
2021-07-11 23:04:40 -05:00
}
private void OnPingReply(object sender, EventArgs args)
{
(sender as RenderPort).PingReply -= new EventHandler(this.OnPingReply);
--this.m_pingRequestCount;
}
private void StartNewBatch()
{
if (this.m_isBatchingMessages || this.m_ports.Count <= 0)
return;
foreach (RenderPort port in this.m_ports)
port.BeginMessageBatch(this.m_batchFillCallback);
this.m_isBatchingMessages = true;
if (this.m_batchBeginCallbacks == null)
return;
this.m_batchBeginCallbacks();
2021-07-11 23:07:04 -05:00
this.m_batchBeginCallbacks = null;
2021-07-11 23:04:40 -05:00
}
internal void FlushBatch() => this.FlushCurrentBatch(false);
private void FlushCurrentBatch(bool stopBatching)
{
if (!this.m_isBatchingMessages)
return;
if (this.m_batchEndCallbacks != null)
{
this.m_batchEndCallbacks();
2021-07-11 23:07:04 -05:00
this.m_batchEndCallbacks = null;
2021-07-11 23:04:40 -05:00
}
this.m_isBatchingMessages = false;
BatchCallback deliveryCallbacks = this.m_batchDeliveryCallbacks;
2021-07-11 23:07:04 -05:00
this.m_batchDeliveryCallbacks = null;
2021-07-11 23:04:40 -05:00
foreach (RenderPort port in this.m_ports)
port.EndMessageBatch(deliveryCallbacks);
if (stopBatching)
return;
this.StartNewBatch();
}
internal void ScheduleBatchFlush()
{
if (this.m_fBatchFlushRequested)
return;
this.AssertOwningThread();
this.DeferredInvoke(this.m_batchFlushInvokeItem, DeferredInvokePriority.Low);
this.m_fBatchFlushRequested = true;
}
internal void ProcessDeferredFlushBatch(object args)
{
this.AssertOwningThread();
if (!this.m_fBatchFlushRequested)
return;
this.FlushBatch();
this.m_fBatchFlushRequested = false;
}
public void NotifyOnBeginBatch(BatchCallback newCallback)
{
if (!this.m_isBatchingMessages)
return;
this.m_batchBeginCallbacks += newCallback;
}
public void NotifyOnEndBatch(BatchCallback newCallback, bool notifyEmptyBatches)
{
if (!this.m_isBatchingMessages)
return;
if (notifyEmptyBatches)
this.ScheduleBatchFlush();
this.m_batchEndCallbacks += newCallback;
}
public void NotifyOnCurrentBatchDelivered(BatchCallback newCallback)
{
if (!this.m_isBatchingMessages)
return;
this.m_batchDeliveryCallbacks += newCallback;
}
private void OnBatchFirstMessage() => this.ScheduleBatchFlush();
private unsafe int OnIncomingMessageBuffer(
IntPtr pData,
uint hContext,
EngineApi.BufferInfo* pBufferInfo,
void* pvBufferData)
{
2021-07-11 23:07:04 -05:00
RenderPort renderPort = null;
2021-07-11 23:04:40 -05:00
for (int index = 0; index < this.m_ports.Count; ++index)
{
RenderPort port = (RenderPort)this.m_ports[index];
if (port.RemoteContext == pBufferInfo->idContextSrc)
{
renderPort = port;
break;
}
}
Debug2.Throw(renderPort != null, "Expected a render port if we are receiving buffers");
renderPort.ProcessMessageBuffer(pBufferInfo, pvBufferData);
return 0;
}
private void OnTimedOut(IntPtr pData)
{
if (this.m_externalTimeoutHandler == null)
return;
this.m_externalTimeoutHandler();
}
internal void AssertOwningThread()
{
}
internal bool IsOwningThread() => this.m_owningThread == Thread.CurrentThread;
internal void DeferredInvoke(Delegate method, object args, DeferredInvokePriority priority) => this.DeferredInvoke(method, args, priority, TimeSpan.FromMilliseconds(0.0));
internal void DeferredInvoke(
SharedRenderObject owner,
Delegate method,
object args,
DeferredInvokePriority priority)
{
this.DeferredInvoke(owner, method, args, priority, TimeSpan.FromMilliseconds(0.0));
}
internal void DeferredInvoke(
Delegate method,
object args,
DeferredInvokePriority priority,
TimeSpan delay)
{
2021-07-11 23:07:04 -05:00
this.DeferredInvoke(null, method, args, priority, delay);
2021-07-11 23:04:40 -05:00
}
internal void DeferredInvoke(
SharedRenderObject instanceOwner,
Delegate method,
object args,
DeferredInvokePriority priority,
TimeSpan delay)
{
if (this.m_owningThread == null)
return;
DeferredInvokeItem deferredInvokeItem = new DeferredInvokeItem(instanceOwner, method, args);
2021-07-11 23:07:04 -05:00
this.m_renderHost.DeferredInvoke(priority, deferredInvokeItem, delay);
2021-07-11 23:04:40 -05:00
}
private void DeferredInvoke(DeferredInvokeItem item, DeferredInvokePriority priority)
{
if (this.m_owningThread == null)
return;
2021-07-11 23:07:04 -05:00
this.m_renderHost.DeferredInvoke(priority, item, TimeSpan.FromMilliseconds(0.0));
2021-07-11 23:04:40 -05:00
}
protected override void Invariant()
{
Debug2.Validate(this.m_owningThread != null, typeof(InvalidOperationException), this.GetType().ToString());
Debug2.Validate(this.m_renderHost != null, typeof(InvalidOperationException), this.GetType().ToString());
Debug2.Validate(this.m_isConnected, typeof(InvalidOperationException), this.GetType().ToString());
2021-07-11 22:59:29 -05:00
}
}
}