// Copy tile to output
        private void CopyToOutput(TileRenderState state, Tensor <float> tensor, Rectangle tile)
        {
            if (tile.Y > 0)
            {
                BlendTopMargin(state, tensor, tile);
            }

            var sx = tile.X > 0 ? Margin : 0;
            var sy = tile.Y > 0 ? Margin : 0;

            var(x, y) = (tile.X, tile.Y);
            var cols = Math.Min(tensor.Width() - sx, Output.Width - tile.X);
            var rows = Math.Min(tensor.Height() - sy, Output.Height - tile.Y);

            var tensorRow  = new ArraySegment <byte>(state.TensorRow, 0, cols * 4);
            var marginLeft = new ArraySegment <byte>(state.OutputRow, 0, sx * 4);

            for (int row = sy; row < rows; ++row)
            {
                _ = tensor.GetRowArgb(tensorRow, sx, row + sy);
                Output.GetRowArgb(marginLeft, tile.X, row + y);
                marginLeft.LinearBlend(tensorRow, tensorRow);
                Output.SetRowArgb(tensorRow, x, row + y);
            }
        }
        /// <summary>
        /// Copy a row of ARGB pixel values to an NHWC-formatted BGR tensor
        /// </summary>
        /// <param name="tensor">NHWC-formatted BGR-valued tensor</param>
        /// <param name="data">Data row containing ARGB pixel values</param>
        /// <param name="x">X-offset to copy to</param>
        /// <param name="y">Y-offset to copy to</param>
        /// <returns>Number of copied elements</returns>
        public static int SetRowArgb(this Tensor <float> tensor, byte[] data, int x, int y)
        {
            Contract.Requires(tensor != null && data != null);
            var memory = ((DenseTensor <float>)tensor).Buffer.Span;
            var width  = tensor.Width();
            var offset = y * width * 3 + x * 3;
            var cols   = Math.Min(data.Length / 4, width);

            for (int i = 0, j = offset; i < cols; ++i)
            {
                memory[j++] = data[i * 4 + 2] / 255f;
                memory[j++] = data[i * 4 + 1] / 255f;
                memory[j++] = data[i * 4 + 0] / 255f;
            }

            return(cols * 3);
        }
        /// <summary>
        /// Copy a row of ARGB pixel values to an NHWC-formatted BGR tensor
        /// </summary>
        /// <param name="tensor">NHWC-formatted BGR-valued tensor</param>
        /// <param name="data">Data row containing ARGB pixel values</param>
        /// <param name="x">X-offset to copy to</param>
        /// <param name="y">Y-offset to copy to</param>
        /// <returns>Number of copied elements</returns>
        public static int SetRowArgb(this Tensor <float> tensor, ArraySegment <byte> data, int x, int y)
        {
            Contract.Requires(tensor != null);
            var memory = ((DenseTensor <float>)tensor).Buffer.Span;
            var source = data.Array;
            var width  = tensor.Width();
            var offset = y * width * 3 + x * 3;
            var cols   = Math.Min(data.Count / 4, width);

            for (int i = 0, j = offset, k = data.Offset; i < cols; ++i, k += 4)
            {
                memory[j++] = source[k + 2] / 255f;
                memory[j++] = source[k + 1] / 255f;
                memory[j++] = source[k + 0] / 255f;
            }

            return(cols * 3);
        }
        // Blend a tile's top rows with previous output
        private void BlendTopMargin(TileRenderState state, Tensor <float> tensor, Rectangle tile)
        {
            var(ix, iy) = (tile.X > 0 ? Margin : 0, Margin);
            var(ox, oy) = (tile.X, tile.Y);
            var delta     = 1.0f / Margin;
            var c         = delta;
            var elements  = (tensor.Width() - ix) * 4;
            var tensorRow = new ArraySegment <byte>(state.TensorRow, 0, elements);
            var outputRow = new ArraySegment <byte>(state.OutputRow, 0, elements);
            var resultRow = new ArraySegment <byte>(state.BufferRow, 0, elements);

            for (int i = 0; i < Margin; ++i, ++iy, ++oy, c += delta)
            {
                _ = tensor.GetRowArgb(tensorRow, ix, iy);
                _ = Output.GetRowArgb(outputRow, ox, oy);
                outputRow.MixArgb(tensorRow, resultRow, c);
                Output.SetRowArgb(resultRow, ox, oy);
            }
        }