/// <summary> /// Read pixel data from <paramref name="intPtr"/> into our local buffer /// and return the total number of bytes read. /// </summary> /// <param name="header"></param> /// <param name="intPtr"></param> /// <returns></returns> internal int ReadPixelData(InteropRenderHeader header, IntPtr intPtr) { var pixelArraySize = header.width * header.height * 3; lock (renderTextureLock) { if (Pixels == IntPtr.Zero) { InteropLogger.Debug($"Allocating {header.width} x {header.height}"); Pixels = Marshal.AllocHGlobal(pixelArraySize); } else if (header.width != Header.width || header.height != Header.height) { // If the inbound data resized - resize our buffer InteropLogger.Debug($"Reallocating {header.width} x {header.height}"); Pixels = Marshal.ReAllocHGlobal(Pixels, new IntPtr(pixelArraySize)); } // Could do a Buffer.MemoryCopy here - but I'm locked to // .NET 4.5 due to the DllExport library we're using. UnsafeNativeMethods.CopyMemory(Pixels, intPtr, (uint)pixelArraySize); Header = header; Frame++; } return(pixelArraySize); }
/// <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(); }