Skip to content

Instantly share code, notes, and snippets.

@noisecrime
Created May 1, 2018 06:58
Show Gist options
  • Save noisecrime/dfa91079f9d7cb9ba0a18729e97453a9 to your computer and use it in GitHub Desktop.
Save noisecrime/dfa91079f9d7cb9ba0a18729e97453a9 to your computer and use it in GitHub Desktop.
Optimizing step for WebProcessing
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;
public class WebcamProcessingTesting : MonoBehaviour
{
[SerializeField]
[Tooltip("Which webcam to use")]
int m_WebcamIndex;
WebCamDevice m_CamDevice;
WebCamTexture m_CamTexture;
[SerializeField]
[Tooltip("the color that sets our threshold values above which we effect a given pixel")]
Color32 m_ColorThreshold;
[SerializeField]
ExampleEffect effect = ExampleEffect.LeftShiftThreshold;
[Range(1, 4)]
[SerializeField]
[Tooltip("the interval of horizontal lines to skip - 1 means process all lines, 2 & 4 create a scanline effect")]
int lineSkip = 2;
[SerializeField]
[Tooltip("select a resolution compatible with your webcam. you will need to move the camera if you change this")]
Vector2Int m_WebcamTextureSize = new Vector2Int(640, 480);
Texture2D m_Texture;
[SerializeField]
Material m_BlankToTextureMat;
JobHandle m_RGBComplementBurstJobHandle;
NativeArray<Color32> m_NativeColors;
NativeSlice<byte> m_NativeRed;
NativeSlice<byte> m_NativeGreen;
NativeSlice<byte> m_NativeBlue;
Color32[] m_Data;
public bool m_EnableSlowMode = true;
public bool m_EnableForcedUpdate = true;
public int m_InnerLoopBatchCount = 1024;
private bool m_DidUpdateThisFrame = false;
void OnEnable()
{
m_Data = new Color32[m_WebcamTextureSize.x * m_WebcamTextureSize.y];
m_NativeColors = new NativeArray<Color32>(m_Data, Allocator.Persistent);
var slice = new NativeSlice<Color32>(m_NativeColors);
m_NativeRed = slice.SliceWithStride<byte>(0);
m_NativeGreen = slice.SliceWithStride<byte>(1);
m_NativeBlue = slice.SliceWithStride<byte>(2);
if (m_WebcamIndex >= WebCamTexture.devices.Length)
m_WebcamIndex = WebCamTexture.devices.Length - 1;
m_CamDevice = WebCamTexture.devices[m_WebcamIndex];
m_CamTexture = new WebCamTexture(m_CamDevice.name, m_WebcamTextureSize.x, m_WebcamTextureSize.y);
Renderer renderer = GetComponent<Renderer>();
renderer.material.mainTexture = m_CamTexture;
m_Texture = new Texture2D(m_WebcamTextureSize.x, m_WebcamTextureSize.y, TextureFormat.RGBA32, false);
m_BlankToTextureMat.mainTexture = m_Texture;
m_InnerLoopBatchCount = (m_WebcamTextureSize.x * m_WebcamTextureSize.y) / 256;
Debug.LogFormat("{0} {1}", m_WebcamTextureSize.x * m_WebcamTextureSize.y, m_InnerLoopBatchCount);
m_CamTexture.Play();
}
void OnDisable()
{
m_CamTexture.Stop();
m_NativeColors.Dispose();
}
void Update()
{
// Debug.LogFormat("isPlaying: {0} didUpdateThisFrame : {1}", m_CamTexture.isPlaying, m_CamTexture.didUpdateThisFrame);
m_DidUpdateThisFrame = (m_EnableForcedUpdate || m_CamTexture.didUpdateThisFrame);
if( !m_DidUpdateThisFrame) return;
// load is one half of our big bottleneck with this method - copying data
m_CamTexture.GetPixels32(m_Data);
m_NativeColors.CopyFrom(m_Data);
// lineskip can only be 1, 2, or 4 - past that the effect doesn't cover the screen
if (lineSkip > 4)
lineSkip = 4;
else if (lineSkip == 3)
lineSkip = 2;
else if (lineSkip == 0)
lineSkip = 1;
switch (effect)
{
case ExampleEffect.ExclusiveOrSelf:
if (lineSkip == 1)
ExclusiveOrSelfProcessWithoutLineSkip(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
else
SelfExclusiveOrProcessing(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
break;
case ExampleEffect.ExclusiveOrThreshold:
if (lineSkip == 1)
ExclusiveOrProcessWithoutLineSkip(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
else
BurstExclusiveOrProcessing(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
break;
case ExampleEffect.LeftShiftThreshold:
if (lineSkip == 1)
LeftShiftProcessWithoutLineSkip(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
else
BurstLeftShiftProcessing(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
break;
case ExampleEffect.RightShiftThreshold:
if(lineSkip == 1)
RightShiftProcessWithoutLineSkip(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
else
BurstRightShiftProcessing(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
break;
case ExampleEffect.ComplementThreshold:
if (lineSkip == 1)
ComplementWithoutLineSkip(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
else
BurstComplementProcessing(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
break;
case ExampleEffect.DefaultPassThrough:
BurstDefaultPassThroughProcessing(m_NativeRed, m_NativeGreen, m_NativeBlue, ref m_RGBComplementBurstJobHandle);
break;
}
}
private void LateUpdate()
{
if( !m_DidUpdateThisFrame) return;
m_RGBComplementBurstJobHandle.Complete();
if ( m_EnableSlowMode )
{
m_NativeColors.CopyTo( m_Data );
m_Texture.SetPixels32( 0, 0, m_WebcamTextureSize.x, m_WebcamTextureSize.y, m_Data );
}
else
{
m_Texture.LoadRawTextureData( m_NativeColors );
}
m_Texture.Apply(false);
}
#region DEFAULTS
void BurstDefaultPassThroughProcessing(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new DefaultPassThroughNoSkipJob()
{
data = r,
};
var greenJob = new DefaultPassThroughNoSkipJob()
{
data = g,
};
var blueJob = new DefaultPassThroughNoSkipJob()
{
data = b,
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
#endregion
void BurstComplementProcessing(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new SelfComplementWithSkipJob()
{
data = r,
threshold = m_ColorThreshold.r,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var greenJob = new SelfComplementWithSkipJob()
{
data = g,
threshold = m_ColorThreshold.g,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var blueJob = new SelfComplementWithSkipJob()
{
data = b,
threshold = m_ColorThreshold.b,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
void BurstLeftShiftProcessing(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new SelfLeftShiftBurstJob()
{
data = r,
threshold = m_ColorThreshold.r,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var greenJob = new SelfLeftShiftBurstJob()
{
data = g,
threshold = m_ColorThreshold.g,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var blueJob = new SelfLeftShiftBurstJob()
{
data = b,
threshold = m_ColorThreshold.b,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
void BurstRightShiftProcessing(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new ThresholdRightShiftBurstJob()
{
data = r,
threshold = m_ColorThreshold.r,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y
};
var greenJob = new ThresholdRightShiftBurstJob()
{
data = g,
threshold = m_ColorThreshold.g,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var blueJob = new ThresholdRightShiftBurstJob()
{
data = b,
threshold = m_ColorThreshold.b,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
void BurstExclusiveOrProcessing(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new ThresholdExclusiveOrBurstJob()
{
data = r,
threshold = m_ColorThreshold.r,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var greenJob = new ThresholdExclusiveOrBurstJob()
{
data = g,
threshold = m_ColorThreshold.g,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var blueJob = new ThresholdExclusiveOrBurstJob()
{
data = b,
threshold = m_ColorThreshold.b,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
void SelfExclusiveOrProcessing(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new SelfExclusiveOrBurstJob()
{
data = r,
threshold = m_ColorThreshold.r,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var greenJob = new SelfExclusiveOrBurstJob()
{
data = g,
threshold = m_ColorThreshold.g,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var blueJob = new SelfExclusiveOrBurstJob()
{
data = b,
threshold = m_ColorThreshold.b,
widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
height = m_WebcamTextureSize.y,
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
void ExclusiveOrProcessWithoutLineSkip(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new ThresholdExclusiveOrNoSkipJob()
{
data = r,
threshold = m_ColorThreshold.r
};
var greenJob = new ThresholdExclusiveOrNoSkipJob()
{
data = g,
threshold = m_ColorThreshold.g
};
var blueJob = new ThresholdExclusiveOrNoSkipJob()
{
data = b,
threshold = m_ColorThreshold.b
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
void ExclusiveOrSelfProcessWithoutLineSkip(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new SelfExclusiveOrNoSkipJob()
{
data = r,
threshold = m_ColorThreshold.r
};
var greenJob = new SelfExclusiveOrNoSkipJob()
{
data = g,
threshold = m_ColorThreshold.g
};
var blueJob = new SelfExclusiveOrNoSkipJob()
{
data = b,
threshold = m_ColorThreshold.b
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
void RightShiftProcessWithoutLineSkip(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new RightShiftNoSkipJob()
{
data = r,
threshold = m_ColorThreshold.r
};
var greenJob = new RightShiftNoSkipJob()
{
data = g,
threshold = m_ColorThreshold.g
};
var blueJob = new RightShiftNoSkipJob()
{
data = b,
threshold = m_ColorThreshold.b
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
void LeftShiftProcessWithoutLineSkip(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new LeftShiftNoSkipJob()
{
data = r,
threshold = m_ColorThreshold.r
};
var greenJob = new LeftShiftNoSkipJob()
{
data = g,
threshold = m_ColorThreshold.g
};
var blueJob = new LeftShiftNoSkipJob()
{
data = b,
threshold = m_ColorThreshold.b
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
void ComplementWithoutLineSkip(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
{
var redJob = new SelfComplementNoSkipJob()
{
data = r,
threshold = m_ColorThreshold.r
};
var greenJob = new SelfComplementNoSkipJob()
{
data = g,
threshold = m_ColorThreshold.g
};
var blueJob = new SelfComplementNoSkipJob()
{
data = b,
threshold = m_ColorThreshold.b
};
var length = m_NativeRed.Length;
var rHandle = redJob.Schedule(length, m_InnerLoopBatchCount);
var gHandle = greenJob.Schedule(length, m_InnerLoopBatchCount, rHandle);
handle = blueJob.Schedule(length, m_InnerLoopBatchCount, gHandle);
}
}
--> PUT BELOW INTO BurstRGBJobs.cs
// Simple pass through ( i.e. does nothing) for testing
[ComputeJobOptimization]
public struct DefaultPassThroughNoSkipJob : IJobParallelFor
{
public NativeSlice<byte> data;
public void Execute(int i)
{
data[i] = (byte)(data[i] - 5);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment