/// <summary> /// Read from the queue into the consumer callable. /// /// <paramref name="consumer"/> is expected to return the number of bytes /// consumed, sans the header. /// </summary> /// <param name="consumer"></param> public int Read(Func <string, InteropMessageHeader, IntPtr, int> consumer) { return(messageConsumer.Read((ptr) => { int bytesRead = 0; // Read target name (varying length string) int targetSize = FastStructure.PtrToStructure <int>(ptr + bytesRead); bytesRead += FastStructure.SizeOf <int>(); string targetName = ""; if (targetSize > 0) { byte[] target = new byte[targetSize]; FastStructure.ReadBytes(target, ptr + bytesRead, 0, targetSize); targetName = Encoding.UTF8.GetString(target); bytesRead += targetSize; } // Read message header var headerSize = FastStructure.SizeOf <InteropMessageHeader>(); var header = FastStructure.PtrToStructure <InteropMessageHeader>(ptr + bytesRead); bytesRead += headerSize; // Call consumer to handle the rest of the payload bytesRead += consumer(targetName, header, ptr + bytesRead); // InteropLogger.Debug($"Consume {bytesRead} bytes - {header.type} for `{targetName}`"); return bytesRead; }, 0)); }
internal static unsafe void PtrToStructure <T>(byte *ptr, out T structure) where T : struct { structure = FastStructure.PtrToStructure <T>((IntPtr)ptr); //var tr = __makeref(structure); //*(IntPtr*)&tr = (IntPtr)ptr; //structure = __refvalue( tr,T); }
private int OnConnect(string target, IntPtr ptr) { unityState = FastStructure.PtrToStructure <InteropUnityState>(ptr); IsConnectedToUnity = true; InteropLogger.Debug($"{target} - {unityState.version} connected. Flavor Blasting."); SendAllSceneData(); return(FastStructure.SizeOf <InteropUnityState>()); }
public virtual void SimpleImageCaptureLoop() { using (var consumer = new CircularBuffer(name: "MySharedMemory", nodeCount: 4, nodeBufferSize: ((8294400 + FastStructure <MetaDataStruct> .Size)) * 2)) // Should be large enough to store 2 full hd raw image data + 4 Size of Struct { Stopwatch stopwatch = new Stopwatch(); do { stopwatch.Reset(); stopwatch.Start(); try { consumer.Read(intPtr => { MetaDataStruct metaData = FastStructure.PtrToStructure <MetaDataStruct>(intPtr); if (metaData.length > 0) { byte[] byteArray = new byte[metaData.length]; FastStructure.ReadArray <byte>(byteArray, intPtr, 0, byteArray.Length); using (var bm = byteArray.ToBitmap(metaData.width, metaData.height, metaData.pitch, metaData.format)) { byte[] compressedJpgByteArray = bm.ToByteCompessedArray(); Bitmap bitmap = compressedJpgByteArray.ToBitmap(); pictureBox1.Invoke(new MethodInvoker(delegate() { if (pictureBox1.Image != null) { pictureBox1.Image.Dispose(); } pictureBox1.Image = bitmap; })); } } return(0); }, timeout: MAX_SLEEP_TIME); } catch (TimeoutException exception) { Console.WriteLine(exception); } catch (Exception ex) { Console.WriteLine(ex); } int timeout = (int)(MAX_SLEEP_TIME - stopwatch.ElapsedMilliseconds); Thread.Sleep(timeout >= 0 ? timeout : 0); } while (true); } }
public T this[int index] { get { if (index >= Length || index < 0) { throw new IndexOutOfRangeException(); } int offset = ElementSize * index; return(FastStructure.PtrToStructure <T>( IntPtr.Add(ptr, offset) )); } }
public void CanAllocHGlobalReadWrite() { IntPtr mem = Marshal.AllocHGlobal(FastStructure.SizeOf <ComplexStructure>()); ComplexStructure n = new ComplexStructure(); n.Compatible.Integer1 = 1; n.Compatible.Bookend = 2; n.FirstElement = 3; n.FinalElement = 9; unsafe { n.Compatible.Contents[0] = 4; n.Compatible.Contents[7] = 5; } FastStructure.StructureToPtr(ref n, mem); // Assert that the reading and writing result in same structure ComplexStructure m = FastStructure.PtrToStructure <ComplexStructure>(mem); Assert.Equal(n, m); Assert.Equal(n.Compatible.Integer1, m.Compatible.Integer1); Assert.Equal(n.Compatible.Bookend, m.Compatible.Bookend); unsafe { Assert.Equal(n.Compatible.Contents[0], m.Compatible.Contents[0]); Assert.Equal(n.Compatible.Contents[7], m.Compatible.Contents[7]); } // Assert that Marshal.PtrToStructure is compatible m = (ComplexStructure)Marshal.PtrToStructure(mem, typeof(ComplexStructure)); Assert.Equal(n, m); Assert.Equal(n.Compatible.Integer1, m.Compatible.Integer1); Assert.Equal(n.Compatible.Bookend, m.Compatible.Bookend); unsafe { Assert.Equal(n.Compatible.Contents[0], m.Compatible.Contents[0]); Assert.Equal(n.Compatible.Contents[7], m.Compatible.Contents[7]); } Marshal.FreeHGlobal(mem); }
/// <summary> /// Read from the viewport image buffer and copy /// pixel data into the appropriate viewport. /// </summary> internal void ConsumePixels() { if (pixelsConsumer == null || pixelsConsumer.ShuttingDown) { return; } pixelsConsumer.Read((ptr) => { var headerSize = FastStructure.SizeOf <InteropRenderHeader>(); var header = FastStructure.PtrToStructure <InteropRenderHeader>(ptr); if (!viewports.ContainsKey(header.viewportId)) { InteropLogger.Warning($"Got render texture for unknown viewport {header.viewportId}"); return(headerSize); } var viewport = viewports[header.viewportId]; var pixelDataSize = viewport.ReadPixelData(header, ptr + headerSize); return(headerSize + pixelDataSize); }, READ_WAIT); }
private int OnUpdateUnityState(string target, IntPtr ptr) { unityState = FastStructure.PtrToStructure <InteropUnityState>(ptr); return(FastStructure.SizeOf <InteropUnityState>()); }
/// <summary> /// Consume a single message off the interop message queue /// </summary> /// <returns>Number of bytes read</returns> private int ConsumeMessage() { var disconnected = false; var bytesRead = messages.Read((target, header, ptr) => { // While not connected - only accept connection requests if (!IsConnected) { if (header.type != RpcRequest.Connect) { Debug.LogWarning($"Unhandled request type {header.type} for {target} - expected RpcRequest.Connect"); } blenderState = FastStructure.PtrToStructure <InteropBlenderState>(ptr); OnConnectToBlender(); return(0); } switch (header.type) { case RpcRequest.UpdateBlenderState: blenderState = FastStructure.PtrToStructure <InteropBlenderState>(ptr); break; case RpcRequest.Disconnect: // Don't call OnDisconnectFromBlender() from within // the read handler - we want to release the read node // safely first before disposing the connection. disconnected = true; break; // Viewport messages case RpcRequest.AddViewport: AddViewport( target, FastStructure.PtrToStructure <InteropViewport>(ptr) ); break; case RpcRequest.RemoveViewport: RemoveViewport(target); break; case RpcRequest.UpdateViewport: GetViewport(target).UpdateFromInterop( FastStructure.PtrToStructure <InteropViewport>(ptr) ); break; case RpcRequest.UpdateVisibleObjects: var visibleObjectIds = new int[header.count]; FastStructure.ReadArray(visibleObjectIds, ptr, 0, header.count); GetViewport(target).SetVisibleObjects( visibleObjectIds ); break; // Object messages case RpcRequest.AddObjectToScene: AddObject( target, FastStructure.PtrToStructure <InteropSceneObject>(ptr) ); break; case RpcRequest.RemoveObjectFromScene: RemoveObject(target); break; case RpcRequest.UpdateSceneObject: UpdateObject( target, FastStructure.PtrToStructure <InteropSceneObject>(ptr) ); break; // Mesh messages case RpcRequest.UpdateTriangles: GetOrCreateMesh(target) .triangles .Resize(header.length) .CopyFrom(ptr, header.index, header.count); break; case RpcRequest.UpdateVertices: GetOrCreateMesh(target) .vertices .Resize(header.length) .CopyFrom(ptr, header.index, header.count); break; case RpcRequest.UpdateNormals: GetOrCreateMesh(target) .normals .Resize(header.length) .CopyFrom(ptr, header.index, header.count); break; case RpcRequest.UpdateUV: GetOrCreateMesh(target) .uv .Resize(header.length) .CopyFrom(ptr, header.index, header.count); break; case RpcRequest.UpdateUV2: GetOrCreateMesh(target) .uv2 .Resize(header.length) .CopyFrom(ptr, header.index, header.count); break; case RpcRequest.UpdateUV3: GetOrCreateMesh(target) .uv3 .Resize(header.length) .CopyFrom(ptr, header.index, header.count); break; case RpcRequest.UpdateUV4: GetOrCreateMesh(target) .uv4 .Resize(header.length) .CopyFrom(ptr, header.index, header.count); break; case RpcRequest.UpdateVertexColors: GetOrCreateMesh(target) .colors .Resize(header.length) .CopyFrom(ptr, header.index, header.count); break; // TODO: ... and so on for weights/bones/etc case RpcRequest.UpdateMesh: GetOrCreateMesh(target).UpdateFromInterop( FastStructure.PtrToStructure <InteropMesh>(ptr) ); break; // Texture messages case RpcRequest.UpdateTexture: GetTexture(target).UpdateFromInterop( FastStructure.PtrToStructure <InteropTexture>(ptr) ); break; case RpcRequest.UpdateTextureData: GetTexture(target).CopyFrom( ptr, header.index, header.count, header.length ); break; default: Debug.LogWarning($"Unhandled request type {header.type} for {target}"); break; } // TODO: Necessary to count bytes? We won't read anything off this // buffer at this point so it's safe to drop the whole thing. // bytesRead will count the header size (indicating a message *was* read) return(0); }); // Handle any disconnects that may have occured during the read if (disconnected) { OnDisconnectFromBlender(); } return(bytesRead); }
/// <summary> /// Handle any messages coming from Blender /// </summary> private void ConsumeMessages() { Profiler.BeginSample("Consume Message"); var disconnected = false; // TODO: Some messages should be skipped if !IsConnected. // Otherwise we may get a bad state. E.g. we see a disconnect // from Blender and THEN some other viewport/object data messages. messages.Read((target, header, ptr) => { ObjectController obj; switch (header.type) { case RpcRequest.Connect: blenderState = FastStructure.PtrToStructure <InteropBlenderState>(ptr); OnConnectToBlender(); break; case RpcRequest.UpdateBlenderState: blenderState = FastStructure.PtrToStructure <InteropBlenderState>(ptr); break; case RpcRequest.Disconnect: // Don't call OnDisconnectFromBlender() from within // the read handler - we want to release the read node // safely first before disposing the connection. disconnected = true; break; case RpcRequest.AddViewport: AddViewport( target, FastStructure.PtrToStructure <InteropViewport>(ptr) ); break; case RpcRequest.RemoveViewport: RemoveViewport(target); break; case RpcRequest.UpdateViewport: GetViewport(target).UpdateFromInterop( FastStructure.PtrToStructure <InteropViewport>(ptr) ); break; case RpcRequest.UpdateVisibleObjects: var visibleObjectIds = new int[header.count]; FastStructure.ReadArray(visibleObjectIds, ptr, 0, header.count); GetViewport(target).SetVisibleObjects( visibleObjectIds ); break; case RpcRequest.AddObjectToScene: AddObject( target, FastStructure.PtrToStructure <InteropSceneObject>(ptr) ); break; case RpcRequest.RemoveObjectFromScene: RemoveObject(target); break; case RpcRequest.UpdateSceneObject: GetObject(target).UpdateFromInterop( FastStructure.PtrToStructure <InteropSceneObject>(ptr) ); break; case RpcRequest.UpdateTriangles: obj = GetObject(target); FastStructure.ReadArray(obj.GetOrCreateTriangleBuffer(), ptr, header.index, header.count); obj.OnUpdateTriangleRange(header.index, header.count); break; case RpcRequest.UpdateVertices: obj = GetObject(target); FastStructure.ReadArray(obj.GetOrCreateVertexBuffer(), ptr, header.index, header.count); obj.OnUpdateVertexRange(header.index, header.count); break; case RpcRequest.UpdateNormals: obj = GetObject(target); FastStructure.ReadArray(obj.GetOrCreateNormalBuffer(), ptr, header.index, header.count); obj.OnUpdateNormalRange(header.index, header.count); break; // TODO: ... and so on for UV/weights default: Debug.LogWarning($"Unhandled request type {header.type} for {target}"); break; } // TODO: Necessary to count bytes? We won't read anything off this // buffer at this point so it's safe to drop the whole thing. return(0); }); // Handle any disconnects that may have occured during the read if (disconnected) { OnDisconnectFromBlender(); } Profiler.EndSample(); }