-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Russell Newman
committed
Nov 19, 2023
1 parent
679cc3b
commit 8e1b2ae
Showing
8 changed files
with
250 additions
and
52 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
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; | ||
} | ||
} | ||
} | ||
} | ||
|
This file contains 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
This file contains 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
Oops, something went wrong.