Skip to content

Instantly share code, notes, and snippets.

@brianmed
Last active January 12, 2022 18:38
Show Gist options
  • Save brianmed/e77e1149fef4569d53ac3a3d5923c582 to your computer and use it in GitHub Desktop.
Save brianmed/e77e1149fef4569d53ac3a3d5923c582 to your computer and use it in GitHub Desktop.
Convert RGBA32 image to Grayscale via ILGPU in C#
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ILGPU" Version="0.10.1" />
</ItemGroup>
</Project>
using System;
using System.Diagnostics;
using System.Linq;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ILGPU;
using ILGPU.Runtime;
// https://sigma.software/about/media/gp-gpu-computing-c
// https://e2eml.school/convert_rgb_to_grayscale.html
namespace ILGpuGrayscale
{
class Program
{
static void Main(string[] args)
{
string imagePath = args[0];
UInt32[] pixels = MemoryMarshal.Cast<byte, UInt32>(File.ReadAllBytes(imagePath)).ToArray();
Stopwatch cpuTotalStopWatch = new Stopwatch();
Stopwatch gpuTotalStopWatch = new Stopwatch();
cpuTotalStopWatch.Start();
foreach (int _ in Enumerable.Range(0, 10))
{
Stopwatch applyStopWatch = new Stopwatch();
applyStopWatch.Start();
TplImageFilter.Apply(pixels, TplImageFilter.Grayscale);
applyStopWatch.Stop();
Console.WriteLine($"\tCPU: {applyStopWatch.Elapsed} [{cpuTotalStopWatch.Elapsed}]");
}
cpuTotalStopWatch.Stop();
Console.WriteLine($"\tCPU: {cpuTotalStopWatch.Elapsed}");
using (IlGpuFilter ilGpuFilter = new())
{
gpuTotalStopWatch.Start();
foreach (int _ in Enumerable.Range(0, 10))
{
Stopwatch applyStopWatch = new Stopwatch();
applyStopWatch.Start();
UInt32[] translatedPixels = ilGpuFilter.Apply(pixels, ilGpuFilter.KernelGrayscale);
applyStopWatch.Stop();
Console.WriteLine($"\tCUDA: {applyStopWatch.Elapsed} [{gpuTotalStopWatch.Elapsed}]");
}
gpuTotalStopWatch.Stop();
Console.WriteLine($"\tCUDA: {gpuTotalStopWatch.Elapsed}");
}
}
}
public class TplImageFilter
{
public static UInt32[] Apply(UInt32[] pixels, Func<UInt32, UInt32> filter)
{
Parallel.For(0, pixels.Length, i => pixels[i] = filter(pixels[i]));
return pixels;
}
public static UInt32 Grayscale(UInt32 pixel)
{
byte red = (byte)(pixel & 0x0000_00FF);
byte green = (byte)((pixel >> 8) & 0x0000_00FF);
byte blue = (byte)((pixel >> 16) & 0x0000_00FF);
byte alpha = (byte)((pixel >> 24) & 0x0000_00FF);
byte gray = (byte)((red * 0.299) + (green * 0.587) + (blue * 0.114));
return (UInt32)(gray << 0) + (UInt32)(gray << 8) + (UInt32)(gray << 16) + (UInt32)(alpha << 24);
}
}
public class IlGpuFilter : IDisposable
{
public readonly Action<ILGPU.Index1, ArrayView<UInt32>> KernelGrayscale;
private readonly Accelerator Accelerator;
public IlGpuFilter()
{
Accelerator = Accelerator.Create(new Context(), Accelerator.Accelerators.First(a => a.AcceleratorType == AcceleratorType.Cuda));
KernelGrayscale = Accelerator.LoadAutoGroupedStreamKernel<ILGPU.Index1, ArrayView<UInt32>>(ApplyGrayscale);
}
private static void ApplyGrayscale(
ILGPU.Index1 index,
ArrayView<UInt32> pixels)
{
pixels[index] = Grayscale(pixels[index]);
}
public UInt32[] Apply(UInt32[] pixels, Action<ILGPU.Index1, ArrayView<UInt32>> kernel)
{
using (MemoryBuffer<UInt32> buffer = this.Accelerator.Allocate<UInt32>(pixels.Length))
{
buffer.CopyFrom(pixels, 0, ILGPU.Index1.Zero, pixels.Length);
kernel(buffer.Length, buffer.View);
// Wait for the kernel to finish...
Accelerator.Synchronize();
return buffer.GetAsArray();
}
}
public static UInt32 Grayscale(UInt32 pixel)
{
byte red = (byte)((pixel >> 0) & 0x0000_00FF);
byte green = (byte)((pixel >> 8) & 0x0000_00FF);
byte blue = (byte)((pixel >> 16) & 0x0000_00FF);
byte alpha = (byte)((pixel >> 24) & 0x0000_00FF);
byte gray = (byte)((byte)(red * 0.299) + (byte)(green * 0.587) + (byte)(blue * 0.114));
return (UInt32)(gray << 0) + (UInt32)(gray << 8) + (UInt32)(gray << 16) + (UInt32)(alpha << 24);
}
public void Dispose()
{
this.Accelerator?.Dispose();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment