Skip to content

Commit

Permalink
opencl context on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
Russell Newman committed Nov 19, 2023
1 parent 679cc3b commit 8e1b2ae
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 52 deletions.
6 changes: 5 additions & 1 deletion GPU/Common/Compute/IContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ public enum Api
CUDA
}

public interface IContext
public interface IContext : IDisposable
{
Api Api { get; }

string ApiVersion { get; }
string ApiName { get; }
string ApiVendor { get; }
}
}

5 changes: 3 additions & 2 deletions GPU/Common/Render/IContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ public interface IContext : IDisposable

Vector3 BackgroundColor {get; set;}
RedrawBackground RedrawBackground {get; set;}

object NativeContext { get; }
object NativeHandle { get; }
IntPtr NativeContext { get; }
IntPtr NativeDeviceContext { get; }
Vector2i FramebufferSize { get; }

event ForceRender ForceRender;
Expand Down
249 changes: 204 additions & 45 deletions GPU/OpenCL/Compute/Context.cs
Original file line number Diff line number Diff line change
@@ -1,109 +1,268 @@
using System.Diagnostics;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.DotNet.PlatformAbstractions;
using Octopus.Player.GPU.Compute;
using Silk.NET.OpenCL;

namespace Octopus.Player.GPU.OpenCL.Compute
{
internal static class Debug
{
static internal void CheckError(int returnValue)
{
System.Diagnostics.Debug.Assert((ErrorCodes)returnValue == ErrorCodes.Success, "OpenCL Error: " + ((ErrorCodes)returnValue).ToString());
}
}

public class Context : GPU.Compute.IContext
{
public Api Api { get { return Api.OpenCL; } }

public string ApiVersion { get; private set; }

public string ApiName{ get; private set; }

public string ApiVendor { get; private set; }
private CL Handle { get; set; }
private nint NativeHandle { get; set; }

public Context()
{

Handle = CL.GetApi();
private bool SupportsGLSharing { get; set; }
private bool SupportsAutoGLSync { get; set; }

uint numPlatforms;
nint[] platforms;
private Context(CL handle, DeviceType deviceType, bool supportsGLSharing, nint[] contextProperties)
{
Handle = handle;
SupportsGLSharing = supportsGLSharing;
int returnValue;
unsafe
{
Handle.GetPlatformIDs(0, null, out numPlatforms);

platforms = new nint[numPlatforms];
fixed (nint* p = platforms)
fixed (nint* properties = contextProperties)
{
Handle.GetPlatformIDs(numPlatforms, p, (uint*)null);
NativeHandle = Handle.CreateContextFromType(properties, deviceType, CallbackHandler, null, out returnValue);
Debug.CheckError(returnValue);
}
Trace.WriteLine("Discovered " + numPlatforms + " OpenCL platform(s)");
}

if (NativeHandle != 0)
OnCreateContext();
}

foreach (var platform in platforms)
private Context(CL handle, nint device, bool supportsGLSharing, nint[] contextProperties)
{
Handle = handle;
SupportsGLSharing = supportsGLSharing;

int returnValue;
unsafe
{
// Query platform devices
uint numDevices;
nint[] devices;
unsafe
fixed (nint* properties = contextProperties)
{
Handle.GetDeviceIDs(platform, DeviceType.Gpu, 0, null, out numDevices);

devices = new nint[numDevices];
fixed(nint* p = devices)
{
Handle.GetDeviceIDs(platform, DeviceType.Gpu, numDevices, p, null);
}
NativeHandle = Handle.CreateContext(properties, 1, device, CallbackHandler, null, out returnValue);
Debug.CheckError(returnValue);
}
}

// Print platform info
var name = GetPlatformInfo(platform, PlatformInfo.Name);
var vendor = GetPlatformInfo(platform, PlatformInfo.Vendor);
var version = GetPlatformInfo(platform, PlatformInfo.Version);
Trace.WriteLine("CL Platform: " + name + ", Vendor: " + vendor + ", Version: " + version + ", " + numDevices + " device(s)");
if (NativeHandle != 0)
OnCreateContext();
}

private void OnCreateContext()
{
/*
SupportsAutoGLSync = DeviceExtensionSupported(Handle, device, "cl_khr_gl_event");
ApiName = GetDeviceInfo(Handle, device, DeviceInfo.Name);
ApiVendor = GetDeviceInfo(Handle, device, DeviceInfo.Vendor);
ApiVersion = GetDeviceInfo(Handle, device, DeviceInfo.Version);
Trace.WriteLine("Created OpenCL context for device: " + ApiName);
*/
}

private unsafe void CallbackHandler(byte* errinfo, void* privateInfo, nuint cb, void* userData)
{

// Print device(s) info
foreach(var device in devices)
{
var deviceName = GetDeviceInfo(device, DeviceInfo.Name);
var deviceVersion = GetDeviceInfo(device, DeviceInfo.Version);
Trace.WriteLine("CL Device: " + deviceName + ", Version: " + deviceVersion );
}
}
}

private string GetDeviceInfo(nint device, DeviceInfo deviceInfo)
static private string GetDeviceInfo(CL handle, nint device, DeviceInfo deviceInfo)
{
nuint parameterSize;
unsafe
{
Handle.GetDeviceInfo(device, deviceInfo, 0, null, out parameterSize);
handle.GetDeviceInfo(device, deviceInfo, 0, null, out parameterSize);
}

byte[] parameter = new byte[parameterSize];
unsafe
{
fixed (byte* p = parameter)
{
Handle.GetDeviceInfo(device, deviceInfo, parameterSize, p, null);
handle.GetDeviceInfo(device, deviceInfo, parameterSize, p, null);
}
}
if (parameter.Length > 0 && parameter.Last() == 0)
parameter = parameter.Take((int)parameterSize - 1).ToArray();
return System.Text.Encoding.ASCII.GetString(parameter);
}

private string GetPlatformInfo(nint platform, PlatformInfo platformInfo)
static private string GetPlatformInfo(CL handle, nint platform, PlatformInfo platformInfo)
{
nuint parameterSize;
unsafe
{
Handle.GetPlatformInfo(platform, platformInfo, 0, null, out parameterSize);
handle.GetPlatformInfo(platform, platformInfo, 0, null, out parameterSize);
}

byte[] parameter = new byte[parameterSize];
unsafe
{
fixed (byte* p = parameter)
{
Handle.GetPlatformInfo(platform, platformInfo, parameterSize, p, null);
handle.GetPlatformInfo(platform, platformInfo, parameterSize, p, null);
}
}
if ( parameter.Length >0 && parameter.Last() == 0 )
if (parameter.Length > 0 && parameter.Last() == 0)
parameter = parameter.Take((int)parameterSize - 1).ToArray();
return System.Text.Encoding.ASCII.GetString(parameter);
}

static private bool PlatformExtensionSupported(CL handle, nint platform, string extension)
{
var extensions = GetPlatformInfo(handle, platform, PlatformInfo.Extensions);
return extensions.Contains(extension);
}

static private bool DeviceExtensionSupported(CL handle, nint device, string extension)
{
var extensions = GetDeviceInfo(handle, device, DeviceInfo.Extensions);
return extensions.Contains(extension);
}

static nint[] GetGPUDevices(CL handle, nint platform)
{
unsafe
{
uint numDevices;
handle.GetDeviceIDs(platform, DeviceType.Gpu, 0, null, out numDevices);

var devices = new nint[numDevices];
fixed (nint* p = devices)
{
handle.GetDeviceIDs(platform, DeviceType.Gpu, numDevices, p, null);
}
return devices;
}
}

static public Context CreateContext(GPU.Render.IContext renderContext)
{
var handle = CL.GetApi();

uint numPlatforms;
nint[] platforms;
unsafe
{
handle.GetPlatformIDs(0, null, out numPlatforms);

platforms = new nint[numPlatforms];
fixed (nint* p = platforms)
{
handle.GetPlatformIDs(numPlatforms, p, (uint*)null);
}
Trace.WriteLine("Discovered " + numPlatforms + " OpenCL platform(s)");
}

var platformsSupportingGLSharing = new List<nint>();
foreach (var platform in platforms)
{
// Query platform devices
var devices = GetGPUDevices(handle, platform);

// Print platform info
var name = GetPlatformInfo(handle, platform, PlatformInfo.Name);
var vendor = GetPlatformInfo(handle, platform, PlatformInfo.Vendor);
var version = GetPlatformInfo(handle, platform, PlatformInfo.Version);
if ( PlatformExtensionSupported(handle, platform, "cl_khr_gl_sharing") )
{
platformsSupportingGLSharing.Add(platform);
Trace.WriteLine("CL Platform: " + name + ", Vendor: " + vendor + ", Version: " + version + ", GL/CL sharing support, " + devices.Length + " device(s)");
} else
Trace.WriteLine("CL Platform: " + name + ", Vendor: " + vendor + ", Version: " + version + ", no CL/GL sharing support, " + devices.Length + " device(s)");

// Print device(s) info
foreach(var device in devices)
{
var deviceName = GetDeviceInfo(handle, device, DeviceInfo.Name);
var deviceVersion = GetDeviceInfo(handle, device, DeviceInfo.Version);
string deviceContextSharing = DeviceExtensionSupported(handle, device, "cl_khr_gl_sharing") ? ", GL/CL sharing support, " : ", no CL/GL sharing support, ";
Trace.WriteLine("CL Device: " + deviceName + ", Version: " + deviceVersion );
}
}

// Pick the first platform with GL sharing, otherwise pick the first platform
var bestPlatform = platformsSupportingGLSharing.Count > 0 ? platformsSupportingGLSharing.First() : platforms.First();
if (platformsSupportingGLSharing.Count == 0)
Trace.WriteLine("Warning, no OpenCL platforms with GL/CL sharing support");
var supportsGLSharing = platformsSupportingGLSharing.Count > 0;

// Get devices for this platform
var bestPlatformDevices = GetGPUDevices(handle, bestPlatform);

// Default context properties
var defaultContextProperties = new nint[] {
(nint)ContextProperties.Platform, bestPlatform
};

// Get shared GL device
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var GLSharingContextProperties = new nint[] {
(nint)Silk.NET.OpenCL.Extensions.KHR.KHR.GLContextKhr, renderContext.NativeContext,
(nint)Silk.NET.OpenCL.Extensions.KHR.KHR.WglHdcKhr, renderContext.NativeDeviceContext,
(nint)ContextProperties.Platform, bestPlatform
};

// Create context
if (bestPlatformDevices.Length == 1 || !supportsGLSharing)
return new Context(handle, DeviceType.Gpu,supportsGLSharing, supportsGLSharing ? GLSharingContextProperties : defaultContextProperties);
else
{
// Get device currently associated with OpenGL Context
var sharingExtension = new Silk.NET.OpenCL.Extensions.KHR.KhrGlSharing(handle.Context);
unsafe
{
nint interopDevice;
nuint interopDeviceCount;
fixed (nint* properties = GLSharingContextProperties)
{
sharingExtension.GetGlcontextInfo(properties, Silk.NET.OpenCL.Extensions.KHR.GlContextInfo.CurrentDeviceForGLContext,
(nuint)sizeof(nint), out interopDevice, out interopDeviceCount);
}

if (interopDevice == 0)
{
Trace.WriteLine("Could not find CL devices for the current GL context, compute not supported");
return null;
}

return new Context(handle, interopDevice, supportsGLSharing, GLSharingContextProperties);
}
}
}

return null;
}

void System.IDisposable.Dispose()
{
if (NativeHandle != 0)
{
Debug.CheckError(Handle.ReleaseContext(NativeHandle));
NativeHandle = 0;
}
}
}
}

1 change: 1 addition & 0 deletions GPU/OpenCL/Player.GPU.OpenCL.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.Mathematics" Version="4.8.1" />
<PackageReference Include="Silk.NET.OpenCL.Extensions.KHR" Version="2.19.0" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
8 changes: 6 additions & 2 deletions GPU/OpenGL/Render/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ public class Context : IContext
public string ApiShadingLanguageVersion { get; private set; }
public Vector3 BackgroundColor { get; set; }
public RedrawBackground RedrawBackground { get; set; }
public object NativeContext { get; private set; }
public object NativeHandle { get; private set; }
public IntPtr NativeContext { get; private set; }
public IntPtr NativeDeviceContext { get; private set; }
public Vector2i FramebufferSize { get { return NativeWindow.FramebufferSize; } }
public event ForceRender ForceRender;

Expand All @@ -64,10 +66,12 @@ public class Context : IContext

private int DefaultVertexArrayHandle { get; set; }

public Context(UI.INativeWindow nativeWindow, object nativeContext)
public Context(UI.INativeWindow nativeWindow, object nativeHandle, IntPtr nativeContext, IntPtr nativeDeviceContext)
{
// Initialise GPU resource lists
NativeWindow = nativeWindow;
NativeHandle = nativeHandle;
NativeDeviceContext = nativeDeviceContext;
NativeContext = nativeContext;
textures = new List<ITexture>();
shaders = new List<IShader>();
Expand Down
Loading

0 comments on commit 8e1b2ae

Please sign in to comment.