using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using UnityEngine.Experimental.Rendering;
using UnityEditor.Bindings.OpenImageIO;
namespace UnityEditor.Recorder.FileFormats
{
///
/// Job to write and image frame
///
unsafe struct WriteImageFrameJob : IJob
{
///
/// List of byte arrays with frame data.
///
public UnsafeList> FramesData;
///
/// Frame width.
///
public uint Width;
///
/// Frame height.
///
public uint Height;
///
/// List of file attributes arrays.
///
public UnsafeList> FileAttributes;
///
/// Path to file.
///
public FixedString4096Bytes FilePath;
///
/// Execute the job.
///
public void Execute()
{
WriteOiioImageFrames(FramesData, Width, Height,
FileAttributes, FilePath);
}
static void WriteOiioImageFrames(UnsafeList> frames, uint width, uint height,
UnsafeList> fileAttributes, FixedString4096Bytes path)
{
var headers = new NativeArray(frames.Length, Allocator.Temp);
for (var i = 0; i < frames.Length; i++)
{
const int sizeHalf = 2;
var channelsCount = (uint)(frames[i].Length / (width * height * sizeHalf));
headers[i] = new OiioWrapper.ImageHeader
{
width = width,
height = height,
channelsCount = channelsCount,
data = new IntPtr(frames[i].GetUnsafeReadOnlyPtr()),
attributesCount = (uint)fileAttributes[i].Length,
attributes = new IntPtr(fileAttributes[i].GetUnsafeReadOnlyPtr())
};
}
OiioWrapper.WriteImage(path, (uint)frames.Length,
(OiioWrapper.ImageHeader*)headers.GetUnsafeReadOnlyPtr());
}
}
///
/// Class to write image frame job buffers
///
class WriteImageFrameJobBuffers : IDisposable
{
///
/// Byte array of image data
///
public UnsafeList> framesData;
///
/// Attributes of file
///
public UnsafeList> fileAttributes;
///
/// Write Frame Job Buffers for an array of images
///
/// Frame width
/// Frame height
/// List of readback formats
/// List of booleans to indicate if the layer needs alpha
/// List of list of attributes
public WriteImageFrameJobBuffers(int width, int height, IList readbackFormats, IList needAlphas,
IList> layersAttributesList)
{
framesData = new UnsafeList>(0, Allocator.Persistent);
fileAttributes = new UnsafeList>(0, Allocator.Persistent);
for (int i = 0; i < layersAttributesList.Count; ++i)
{
var bufferSize = ComputeBufferSize(width, height, readbackFormats[i], needAlphas[i]);
framesData.Add(new NativeArray(bufferSize, Allocator.Persistent));
var layerAttributes =
new NativeArray(layersAttributesList[i].Count, Allocator.Persistent);
layerAttributes.CopyFrom(layersAttributesList[i].ToArray());
fileAttributes.Add(layerAttributes);
}
}
static int ComputeBufferSize(int width, int height, GraphicsFormat format, bool needAlpha)
{
var mipmapSize = (int)GraphicsFormatUtility.ComputeMipmapSize(width, height, format);
if (format is GraphicsFormat.R16G16B16A16_SFloat && !needAlpha)
{
return mipmapSize * 3 / 4;
}
return mipmapSize;
}
///
/// Disposes of the frame.
///
public void Dispose()
{
if (framesData.IsCreated)
{
foreach (var frame in framesData)
{
if (frame.IsCreated)
{
frame.Dispose();
}
}
framesData.Dispose();
}
if (fileAttributes.IsCreated)
{
foreach (var attrib in fileAttributes)
{
if (attrib.IsCreated)
{
attrib.Dispose();
}
}
fileAttributes.Dispose();
}
}
}
}