Exemple #1
0
        public void ReadWrite_MyTestStruct_DataMatches()
        {
            string name     = Guid.NewGuid().ToString();
            int    nodeSize = Marshal.SizeOf(typeof(MyTestStruct));

            using (var smr = new CircularBuffer(name, 2, nodeSize))
                using (var sm2 = new CircularBuffer(name))
                {
                    MyTestStruct obj = new MyTestStruct
                    {
                        Prop1 = 1,
                        Prop2 = 2,
                        Prop3 = 3,
                        Prop4 = 4
                    };

                    smr.Write(ref obj);

                    MyTestStruct read;
                    int          bytesRead = sm2.Read(out read);
                    if (bytesRead > 0)
                    {
                        Assert.AreEqual(FastStructure.SizeOf <MyTestStruct>(), bytesRead);
                        Assert.AreEqual(obj, read);
                    }
                    else
                    {
                        Assert.Fail();
                    }
                }
        }
Exemple #2
0
        internal unsafe void WriteArray <T>(long position, T[] buffer, int index, int count)
            where T : struct
        {
            uint elementSize = (uint)Marshal.SizeOf(typeof(T));

            if (position > this._view.Size - (elementSize * count))
            {
                throw new ArgumentOutOfRangeException("position");
            }

            try
            {
                byte *ptr = null;
                _view.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);
                ptr += _view.ViewStartOffset + position;

                FastStructure.WriteArray <T>((IntPtr)ptr, buffer, index, count);

                //for (var i = 0; i < count; i++)
                //{
                //    StructureToPtr(ref buffer[index + i], ptr + (i * elementSize));
                //}
            }
            finally
            {
                _view.SafeMemoryMappedViewHandle.ReleasePointer();
            }
        }
Exemple #3
0
        internal unsafe void ReadArray <T>(long position, T[] buffer, int index, int count)
            where T : struct
        {
            uint elementSize = (uint)FastStructure.SizeOf <T>();

            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (position > this._view.Size - (elementSize * count))
            {
                throw new ArgumentOutOfRangeException("position");
            }
            try
            {
                byte *ptr = null;
                _view.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);
                ptr += _view.ViewStartOffset + position;

                FastStructure.ReadArray <T>(buffer, (IntPtr)ptr, index, count);

                //for (var i = 0; i < count; i++)
                //{
                //    PtrToStructure(ptr + (i * elementSize), out buffer[index + i]);
                //}
            }
            finally
            {
                _view.SafeMemoryMappedViewHandle.ReleasePointer();
            }
        }
Exemple #4
0
        public bool ReplaceOrQueue <T>(RpcRequest type, string target, ref T data) where T : struct
        {
            var header = new InteropMessageHeader {
                type  = type,
                index = 0,
                count = 0
            };

            var payload = FastStructure.ToBytes(ref data);

            // If it's already queued, replace the payload
            var queued = FindQueuedMessage(target, ref header);

            if (queued != null)
            {
                queued.payload = payload;
                return(true);
            }

            outboundQueue.Enqueue(new InteropMessage
            {
                target  = target,
                header  = header,
                payload = payload
            });

            return(false);
        }
Exemple #5
0
        /// <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));
        }
Exemple #6
0
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <param name="target"></param>
        /// <param name="buffer"></param>
        public void QueueArray <T>(RpcRequest type, string target, IArray <T> buffer) where T : struct
        {
            var headerSize  = FastStructure.SizeOf <InteropMessageHeader>();
            var elementSize = FastStructure.SizeOf <T>();

            if (headerSize + elementSize * buffer.Length > messageProducer.NodeBufferSize)
            {
                throw new Exception($"Cannot queue {buffer.Length} elements of {typeof(T)} - will not fit in a single message");
            }

            // Construct a header with metadata for the array
            var header = new InteropMessageHeader {
                type   = type,
                length = buffer.MaxLength,
                index  = buffer.Offset,
                count  = buffer.Length
            };

            // Remove any queued messages with the same outbound header
            RemoveQueuedMessage(target, ref header);

            InteropLogger.Debug($"    QA-> {target}:{type:F}");
            outboundQueue.Enqueue(new InteropMessage
            {
                target   = target,
                header   = header,
                producer = (tar, hdr, ptr) => {
                    buffer.CopyTo(ptr, 0, buffer.Length);
                    return(elementSize * buffer.Length);
                }
            });
        }
Exemple #7
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);
 }
Exemple #8
0
        /// <summary>
        /// Queue an outbound message containing one or more <typeparamref name="T"/> values.
        ///
        /// <para>
        ///     If we cannot fit the entire dataset into a single message, and
        ///     <paramref name="allowSplitMessages"/> is true then the payload will
        ///     be split into multiple messages, each with a distinct
        ///     <see cref="InteropMessageHeader.index"/> and <see cref="InteropMessageHeader.count"/>
        ///     range.
        /// </para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <param name="target"></param>
        /// <param name="data"></param>
        /// <param name="allowSplitMessages"></param>
        public bool ReplaceOrQueueArray <T>(RpcRequest type, string target, T[] data, bool allowSplitMessages) where T : struct
        {
            var headerSize  = FastStructure.SizeOf <InteropMessageHeader>();
            var elementSize = FastStructure.SizeOf <T>();

            // TODO: Splitting. Right now assume fit or fail.
            if (headerSize + elementSize * data.Length > messageProducer.NodeBufferSize)
            {
                throw new Exception($"Cannot queue {data.Length} elements of {typeof(T)} - will not fit in a single message");
            }

            var header = new InteropMessageHeader {
                type  = type,
                index = 0,
                count = data.Length
            };

            // TODO: If the source array size changes - find queued won't be correct.

            // We assume ReplaceOrQueue because of the below TODO - multiple queued arrays
            // would be pointing to the same data anyway.

            // If it's already queued, we don't need to do anything.
            var queued = FindQueuedMessage(target, ref header);

            if (queued != null)
            {
                return(true);
            }

            outboundQueue.Enqueue(new InteropMessage
            {
                target   = target,
                header   = header,
                producer = (tar, hdr, ptr) => {
                    if (hdr.count < 1 || hdr.index + hdr.count > data.Length)
                    {
                        throw new Exception($"Producer out of range of dataset - {hdr.type} - {tar}");
                    }
                    // TODO: My concern here would be what happens if the buffer changes before this is sent?
                    // This would send the updated buffer - BUT that probably wouldn't be a problem because
                    // we're trying to send the most recent data at all times anyway, right?
                    // Even if it's sitting in queue for a while.

                    // Also seems like this should be an implicit QueueOrReplace - because if multiple
                    // queued messsages point to the same array - they're going to send the same array data.

                    // Could leave this up to the QueueArray caller - passing in this Func<...>
                    // and we're just responsible for adjusting the header to the ranges that fit.
                    FastStructure.WriteArray(ptr, data, hdr.index, hdr.count);
                    return(elementSize * hdr.count);
                }
            });

            return(false);
        }
Exemple #9
0
        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>());
        }
Exemple #10
0
 /// <summary>
 /// Queue an outbound message containing a <typeparamref name="T"/> payload
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="target"></param>
 /// <param name="type"></param>
 /// <param name="data"></param>
 public void Queue <T>(RpcRequest type, string target, ref T data) where T : struct
 {
     outboundQueue.Enqueue(new InteropMessage
     {
         target = target,
         header = new InteropMessageHeader {
             type  = type,
             index = 0,
             count = 0
         },
         payload = FastStructure.ToBytes(ref data)
     });
 }
Exemple #11
0
        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);
            }
        }
Exemple #12
0
        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)
                           ));
            }
        }
        protected void ProcessFrame(int width, int height, int pitch, PixelFormat format, IntPtr pBits)
        {
            if (format == PixelFormat.Undefined)
            {
                DebugMessage("Unsupported render target format");
                return;
            }

            if (pBits == IntPtr.Zero)
            {
                DebugMessage("No image data");
                return;
            }

            // Copy the image data from the buffer
            int size = height * pitch;
            var data = new byte[size];

            try
            {
                try
                {
                    Marshal.Copy(pBits, data, 0, size);
                    producer.Write(intPtr =>
                    {
                        MetaDataStruct metaData = new MetaDataStruct(data.Length, width, height, pitch, format);
                        FastStructure.StructureToPtr(ref metaData, intPtr);
                        intPtr += FastStructure <MetaDataStruct> .Size;
                        FastStructure.WriteArray <byte>(intPtr, data, 0, data.Length);
                        return(0);
                    }, 0); // skip frame if we cannot write to circular buffer immediately
                }
                catch (TimeoutException)
                {
                    // If we could not acquire write lock skip frame
                }
                catch (AccessViolationException)
                {
                    // In this specifc case we are ignoring CSE (corrupted state exception)
                    // It could happen during Window resizing.
                    // If someone knows are better way please feel free to contribute
                    // Because there is a timout in the resizing hook this exception should never be thrown
                }
            }
            catch (ObjectDisposedException)
            {
                // swallow exception to not crash hooked process
            }
        }
Exemple #14
0
        /// <summary>
        /// Copy the RenderTexture data from the ViewportController into shared memory with Blender.
        ///
        /// <para>
        ///     The <paramref name="pixelsRGB24Func"/> callback is executed IFF we have room in the
        ///     buffer to write - letting us skip the heavy pixel copy operations if the consumer
        ///     is backed up in processing data.
        /// </para>
        /// </summary>
        internal void PublishRenderTexture(ViewportController viewport, Func <byte[]> pixelsRGB24Func)
        {
            if (!IsConnected)
            {
                Debug.LogWarning("Cannot send RT - No connection");
            }

            Profiler.BeginSample("Write wait on pixelsProducer");

            int bytesWritten = pixelsProducer.Write((ptr) => {
                // If we have a node we can write on, actually do the heavy lifting
                // of pulling the pixel data from the RenderTexture (in the callback)
                // and write into the buffer.
                var pixelsRGB24 = pixelsRGB24Func();

                Profiler.BeginSample("Write Pixels into Shared Memory");

                // Pack a header into shared memory
                var header = new InteropRenderHeader
                {
                    viewportId = viewport.ID,
                    width      = viewport.Width,
                    height     = viewport.Height
                };

                var headerSize = FastStructure.SizeOf <InteropRenderHeader>();
                FastStructure.WriteBytes(ptr, FastStructure.ToBytes(ref header), 0, headerSize);

                // Copy render image data into shared memory
                FastStructure.WriteBytes(ptr + headerSize, pixelsRGB24, 0, pixelsRGB24.Length);

                /*InteropLogger.Debug($"Writing {pixelsRGB24.Length} bytes with meta {header.width} x {header.height} and pix 0 is " +
                 *  $"{pixelsRGB24[0]}, {pixelsRGB24[1]}, {pixelsRGB24[2]}"
                 * );*/

                Profiler.EndSample();
                return(headerSize + pixelsRGB24.Length);
            }, WRITE_WAIT);

            /*
             * if (bytesWritten < 1)
             * {
             *  Debug.LogWarning("pixelsProducer buffer is backed up. Skipped write.");
             * }*/

            Profiler.EndSample();
        }
        /// <summary>
        /// Estimate how much of shared memory will be allocated between Unity and Blender given current settings
        /// </summary>
        public string CalculateSharedMemoryUsage()
        {
            var bufferHeaderSize  = FastStructure.SizeOf <SharedHeader>();
            var messageBufferSize = nodeSize * nodeCount + bufferHeaderSize;
            var pixelsBufferSize  = pixelsNodeCount * PixelsNodeSizeBytes + bufferHeaderSize;

            var expectedSharedMemorySize = (messageBufferSize + pixelsBufferSize) / 1024.0 / 1024.0;
            var units = "MB";

            if (expectedSharedMemorySize > 1024)
            {
                expectedSharedMemorySize /= 1024.0;
                units = "GB";
            }

            return($"{expectedSharedMemorySize:F2} {units}");
        }
        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);
        }
Exemple #17
0
        /// <summary>
        /// Fill the buffer from the source memory location and mark dirty
        /// </summary>
        /// <param name="ptr">The source memory location</param>
        /// <param name="index">The start index within this buffer</param>
        /// <param name="count">The number of elements to read</param>
        public void CopyFrom(IntPtr src, int index, int count)
        {
            if (Offset > 0)
            {
                throw new NotImplementedException(
                          "Cannot CopyFrom into a subarray"
                          );
            }

            if (index + count > Length)
            {
                throw new OverflowException(
                          $"index({index}) + count({count}) is larger than Length({Length})"
                          );
            }

            FastStructure.ReadArray(data, src, index, count);
            Dirty(index, index + count - 1);
        }
Exemple #18
0
        /// <summary>
        /// Write <paramref name="message"/> into the next available
        /// node's buffer at <paramref name="ptr"/>.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="ptr"></param>
        /// <returns></returns>
        private int WriteMessage(InteropMessage message, IntPtr ptr)
        {
            int bytesWritten = 0;

            // Write the target name (varying length string)
            byte[] target    = Encoding.UTF8.GetBytes(message.target);
            int    targetLen = target.Length;

            FastStructure.StructureToPtr(ref targetLen, ptr + bytesWritten);
            bytesWritten += FastStructure.SizeOf <int>();

            if (targetLen > 0)
            {
                FastStructure.WriteBytes(ptr + bytesWritten, target, 0, targetLen);
                bytesWritten += targetLen;
            }

            // Write the message header
            var headerSize = FastStructure.SizeOf <InteropMessageHeader>();
            var header     = message.header;

            FastStructure.StructureToPtr(ref header, ptr + bytesWritten);
            bytesWritten += headerSize;

            // If there's a custom producer, execute it for writing the payload
            if (message.producer != null)
            {
                bytesWritten += message.producer(message.target, header, ptr + bytesWritten);
            }

            // If there's a payload included with the message, copy it
            if (message.payload != null)
            {
                FastStructure.WriteBytes(ptr + bytesWritten, message.payload, 0, message.payload.Length);
                bytesWritten += message.payload.Length;
            }

            // InteropLogger.Debug($"Produce {bytesWritten} bytes - {header.type} for `{message.target}`");

            return(bytesWritten);
        }
Exemple #19
0
        /// <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);
        }
Exemple #20
0
        public bool ReplaceOrQueue <T>(RpcRequest type, string target, ref T data) where T : struct
        {
            var header = new InteropMessageHeader {
                type   = type,
                index  = 0,
                length = 0,
                count  = 0
            };

            var payload = FastStructure.ToBytes(ref data);

            // If it's already queued, replace the payload

            /*var queued = FindQueuedMessage(target, ref header);
             * if (queued != null)
             * {
             *  queued.payload = payload;
             *  return true;
             * }*/

            // Remove the old one to then queue up one at the end
            // This ensures messages that are queued up together
            // remain in their queued order.
            RemoveQueuedMessage(target, ref header);


            InteropLogger.Debug($"    ROQ-> {target}:{header.type:F}");
            outboundQueue.Enqueue(new InteropMessage
            {
                target  = target,
                header  = header,
                payload = payload
            });

            return(false);
        }
Exemple #21
0
        private int OnUpdateUnityState(string target, IntPtr ptr)
        {
            unityState = FastStructure.PtrToStructure <InteropUnityState>(ptr);

            return(FastStructure.SizeOf <InteropUnityState>());
        }
Exemple #22
0
        /// <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();
        }
Exemple #23
0
        private void DrawAdvanced()
        {
            EditorGUILayout.LabelField("Shared Memory Buffer Settings", EditorStyles.boldLabel);

            EditorGUI.BeginDisabledGroup(Sync.IsSetup);

            Settings.bufferName = EditorGUILayout.TextField("Buffer Name", Settings.bufferName);

            Settings.nodeCount = EditorGUILayout.IntSlider(
                "Node Count",
                Settings.nodeCount,
                MIN_NODE_COUNT,
                MAX_NODE_COUNT
                );

            Settings.nodeSize = EditorGUILayout.IntPopup(
                "Node Size",
                Settings.nodeSize,
                new string[] { "1 MB", "2 MB", "4 MB", "8 MB", "16 MB", "32 MB", "64 MB" },
                new int[] { 1, 2, 4, 8, 16, 32, 64 }
                );

            Settings.pixelsNodeCount = EditorGUILayout.IntSlider(
                "Pixels Node Count",
                Settings.pixelsNodeCount,
                MIN_NODE_COUNT,
                MAX_NODE_COUNT
                );

            Settings.maxViewportWidth = EditorGUILayout.IntField(
                "Max Viewport Width",
                Settings.maxViewportWidth
                );

            Settings.maxViewportHeight = EditorGUILayout.IntField(
                "Max Viewport Height",
                Settings.maxViewportHeight
                );

            var bufferHeaderSize  = FastStructure.SizeOf <SharedHeader>();
            var messageBufferSize = Settings.NodeSizeBytes * Settings.nodeCount + bufferHeaderSize;
            var pixelsBufferSize  = Settings.pixelsNodeCount * Settings.PixelsNodeSizeBytes + bufferHeaderSize;

            var expectedSharedMemorySize = (messageBufferSize + pixelsBufferSize) / 1024.0 / 1024.0;
            var units = "MB";

            if (expectedSharedMemorySize > 1024)
            {
                expectedSharedMemorySize /= 1024.0;
                units = "GB";
            }

            EditorGUI.EndDisabledGroup();

            EditorGUILayout.HelpBox(
                $"{expectedSharedMemorySize:F2} {units} of shared memory will be used between Unity and Blender",
                MessageType.Info
                );

            if (Sync.IsSetup)
            {
                EditorGUILayout.HelpBox(
                    "The above settings cannot be modified while Coherence is running",
                    MessageType.Warning
                    );
            }
        }
Exemple #24
0
 /// <summary>
 /// Copy a subset of this buffer to the given memory address.
 ///
 /// The current <see cref="Offset"/> will be applied during copy.
 /// </summary>
 /// <param name="ptr">The destination memory location</param>
 /// <param name="index">The start index within this buffer</param>
 /// <param name="count">The number of elements to write</param>
 public void CopyTo(IntPtr dst, int index, int count)
 {
     FastStructure.WriteArray(dst, data, Offset + index, count);
 }
Exemple #25
0
 internal static unsafe void StructureToPtr <T>(ref T structure, byte *ptr)
     where T : struct
 {
     FastStructure.StructureToPtr <T>(ref structure, (IntPtr)ptr);
 }
Exemple #26
0
        /// <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);
        }