// 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> /// Process an effect graph using tiled input /// </summary> /// <param name="graph">Fully configured effect graph instance</param> public void Process(EffectGraph graph) { Contract.Requires(graph != null); var state = new TileRenderState(this); var tiles = GetTiles(new Size(Input.Width, Input.Height), TileSize); int index = 0; graph.Update += GraphUpdate; foreach (var tile in tiles) { ++index; var expanded = AddMargins(tile); state.SetTileSize(expanded.Size); graph.Params.Content = Input.CopyToTensor(state.Tensor, expanded); var result = graph.Run(index == 1); CopyToOutput(state, result, tile); } graph.Update -= GraphUpdate; void GraphUpdate(object sender, EffectGraphEventArgs e) { var args = new TileEventArgs(e, tiles[index - 1], index, tiles.Count); Update?.Invoke(this, args); } }
// 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); } }