Created
May 1, 2018 06:58
-
-
Save noisecrime/dfa91079f9d7cb9ba0a18729e97453a9 to your computer and use it in GitHub Desktop.
Optimizing step for WebProcessing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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