diff --git a/Samples/MiniFramework/VulkanApp.cs b/Samples/MiniFramework/VulkanApp.cs
index fd39069..613d859 100644
--- a/Samples/MiniFramework/VulkanApp.cs
+++ b/Samples/MiniFramework/VulkanApp.cs
@@ -5,6 +5,7 @@
using System.Linq;
using VulkanCore.Ext;
using VulkanCore.Khr;
+using VulkanCore.Mvk;
namespace VulkanCore.Samples
{
@@ -49,8 +50,7 @@ public void Initialize(IVulkanAppHost host)
{
Host = host;
#if DEBUG
- //At the moment molten-vk doesn't support the debug extension
- bool debug = host.Platform != Platform.MacOS;
+ const bool debug = true;
#else
const bool debug = false;
#endif
@@ -64,6 +64,16 @@ public void Initialize(IVulkanAppHost host)
ImageAvailableSemaphore = ToDispose(Context.Device.CreateSemaphore());
RenderingFinishedSemaphore = ToDispose(Context.Device.CreateSemaphore());
+ if(host.Platform == Platform.MacOS)
+ {
+ //Setup MoltenVK specific device configuration.
+ MVKDeviceConfiguration deviceConfig = Context.Device.GetMVKDeviceConfiguration();
+ deviceConfig.DebugMode = debug;
+ deviceConfig.PerformanceTracking = debug;
+ deviceConfig.PerformanceLoggingFrameCount = debug ? 300 : 0;
+ Context.Device.SetMVKDeviceConfiguration(deviceConfig);
+ }
+
_initializingPermanent = false;
// Calling ToDispose here registers the resource to be automatically disposed on events
// such as window resize.
@@ -171,7 +181,9 @@ private Instance CreateInstance(bool debug)
}
var createInfo = new InstanceCreateInfo();
- if (debug)
+
+ //Currently MoltenVK (used for MacOS) doesn't support the debug layer.
+ if (debug && Host.Platform != Platform.MacOS)
{
var availableLayers = Instance.EnumerateLayerProperties();
createInfo.EnabledLayerNames = new[] { Constant.InstanceLayer.LunarGStandardValidation }
@@ -197,7 +209,8 @@ private Instance CreateInstance(bool debug)
private DebugReportCallbackExt CreateDebugReportCallback(bool debug)
{
- if (!debug) return null;
+ //Currently MoltenVK (used for MacOS) doesn't support the debug layer.
+ if (!debug || Host.Platform == Platform.MacOS) return null;
// Attach debug callback.
var debugReportCreateInfo = new DebugReportCallbackCreateInfoExt(
@@ -221,7 +234,7 @@ private SurfaceKhr CreateSurface()
case Platform.Win32:
return Instance.CreateWin32SurfaceKhr(new Win32SurfaceCreateInfoKhr(Host.InstanceHandle, Host.WindowHandle));
case Platform.MacOS:
- return Mvk.InstanceExtensions.CreateMacOSSurfaceMvk(Instance, new Mvk.MacOSSurfaceCreateInfoMvk { View = Host.WindowHandle });
+ return Instance.CreateMacOSSurfaceMvk(new MacOSSurfaceCreateInfoMvk(Host.WindowHandle));
default:
throw new NotImplementedException();
}
diff --git a/Src/Mvk/DeviceExtensions.cs b/Src/Mvk/DeviceExtensions.cs
new file mode 100644
index 0000000..d8a1c92
--- /dev/null
+++ b/Src/Mvk/DeviceExtensions.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace VulkanCore.Mvk
+{
+ ///
+ /// Provides Brenwill Workshop specific extension methods for the class.
+ ///
+ public static unsafe class DeviceExtensions
+ {
+ ///
+ /// Get the current structure for this device
+ ///
+ /// The device to get configuration from.
+ /// The configuration structure
+ public static MVKDeviceConfiguration GetMVKDeviceConfiguration(this Device device)
+ {
+ MVKDeviceConfiguration configuration;
+ vkGetMoltenVKDeviceConfigurationMVK(device)(device, &configuration);
+ return configuration;
+ }
+
+ ///
+ /// Sets the current structure for this device
+ ///
+ /// The device to set the configuration to.
+ /// Structure containing the configuration parameters.
+ /// Vulkan returns an error code.
+ public static void SetMVKDeviceConfiguration(this Device device, MVKDeviceConfiguration configuration)
+ {
+ Result result = vkSetMoltenVKDeviceConfigurationMVK(device)(device, &configuration);
+ VulkanException.ThrowForInvalidResult(result);
+ }
+
+ private delegate void vkGetMoltenVKDeviceConfigurationMVKDelegate(IntPtr device, MVKDeviceConfiguration* configuration);
+ private static vkGetMoltenVKDeviceConfigurationMVKDelegate vkGetMoltenVKDeviceConfigurationMVK(Device device) => device.GetProc(nameof(vkGetMoltenVKDeviceConfigurationMVK));
+
+ private delegate Result vkSetMoltenVKDeviceConfigurationMVKDelegate(IntPtr device, MVKDeviceConfiguration* configuration);
+ private static vkSetMoltenVKDeviceConfigurationMVKDelegate vkSetMoltenVKDeviceConfigurationMVK(Device device) => device.GetProc(nameof(vkSetMoltenVKDeviceConfigurationMVK));
+ }
+}
diff --git a/Src/Mvk/InstanceExtensions.cs b/Src/Mvk/InstanceExtensions.cs
index 33db547..49ff20b 100644
--- a/Src/Mvk/InstanceExtensions.cs
+++ b/Src/Mvk/InstanceExtensions.cs
@@ -135,6 +135,18 @@ public struct MacOSSurfaceCreateInfoMvk
///
public IntPtr View;
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// Pointer to a NSView that is backed by a CALayer instance of type CAMetalLayer.
+ public MacOSSurfaceCreateInfoMvk(IntPtr view)
+ {
+ View = view;
+ Type = StructureType.MacOSSurfaceCreateInfoMvk;
+ Next = IntPtr.Zero;
+ Flags = 0;
+ }
+
internal void Prepare()
{
Type = StructureType.MacOSSurfaceCreateInfoMvk;
diff --git a/Src/Mvk/MVKDeviceConfiguration.cs b/Src/Mvk/MVKDeviceConfiguration.cs
new file mode 100644
index 0000000..9ad1e23
--- /dev/null
+++ b/Src/Mvk/MVKDeviceConfiguration.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace VulkanCore.Mvk
+{
+ ///
+ /// Structure specifying MoltenVK configuration settings.
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MVKDeviceConfiguration
+ {
+ ///
+ /// If enabled, several debugging capabilities will be enabled. Shader code will be logged
+ /// during Runtime Shader Conversion. Adjusts settings that might trigger Metal validation but
+ /// are otherwise acceptable to Metal runtime. Improves support for Xcode GPU Frame Capture.
+ /// Default value is true in the presence of the DEBUG build setting, and false otherwise.
+ ///
+ public Bool DebugMode;
+ ///
+ /// If enabled, MSL vertex shader code created during Runtime Shader Conversion will flip the
+ /// Y-axis of each vertex, as Vulkan coordinate system is inverse of OpenGL. Default is true.
+ ///
+ public Bool ShaderConversionFlipVertexY;
+ ///
+ /// If enabled, queue command submissions (vkQueueSubmit() and vkQueuePresentKHR()) will be
+ /// processed on the thread that called the submission function. If disabled, processing will
+ /// be dispatched to a GCD dispatch_queue whose priority is determined by
+ /// VkDeviceQueueCreateInfo::pQueuePriorities during vkCreateDevice(). This setting affects how
+ /// much command processing should be performed on the rendering thread, or offloaded to a secondary
+ /// thread. Default value is false, and command processing will be handled on a prioritizable queue thread.
+ ///
+ public Bool SynchronousQueueSubmits;
+ ///
+ /// Metal allows only 8192 occlusion queries per MTLBuffer. If enabled, MoltenVK allocates a MTLBuffer
+ /// for each query pool, allowing each query pool to support 8192 queries, which may slow
+ /// performance or cause unexpected behaviour if the query pool is not established prior to a
+ /// Metal renderpass, or if the query pool is changed within a Metal renderpass. If disabled,
+ /// one MTLBuffer will be shared by all query pools, which improves performance, but limits the total
+ /// device queries to 8192. Default value is true.
+ ///
+ public Bool SupportLargeQueryPools;
+ ///
+ /// If enabled, each surface presentation is scheduled using a command buffer. Enabling this may
+ /// improve rendering frame synchronization, but may result in reduced frame rates. Default value
+ /// is false if the MVK_PRESENT_WITHOUT_COMMAND_BUFFER build setting is defined when MoltenVK is
+ /// compiled, and true otherwise. By default the MVK_PRESENT_WITHOUT_COMMAND_BUFFER build setting
+ /// is not defined and the value of this setting is true.
+ ///
+ public Bool PresentWithCommandBuffer;
+ ///
+ /// If enabled, a MoltenVK logo watermark will be rendered on top of the scene. This can be
+ /// enabled for publicity during demos. Default value is true if the MVK_DISPLAY_WATERMARK
+ /// build setting is defined when MoltenVK is compiled, and false otherwise. By default the
+ /// MVK_DISPLAY_WATERMARK build setting is not defined.
+ ///
+ public Bool DisplayWatermark;
+ ///
+ /// If enabled, per-frame performance statistics are tracked, optionally logged, and can be retrieved
+ /// via the vkGetSwapchainPerformanceMVK() function, and various performance statistics are tracked,
+ /// logged, and can be retrieved via the vkGetPerformanceStatisticsMVK() function. Default value
+ /// is true in the presence of the DEBUG build setting, and false otherwise.
+ ///
+ public Bool PerformanceTracking;
+ ///
+ /// If non-zero, performance statistics will be periodically logged to the console, on a repeating
+ /// cycle of this many frames per swapchain. The performanceTracking capability must also be enabled.
+ /// Default value is 300 in the presence of the DEBUG build setting, and zero otherwise.
+ ///
+ public UInt32 PerformanceLoggingFrameCount;
+ ///
+ /// The maximum amount of time, in nanoseconds, to wait for a Metal library, function or pipeline state
+ /// object to be compiled and created. If an internal error occurs with the Metal compiler, it can stall
+ /// the thread for up to 30 seconds. Setting this value limits the delay to that amount of time.
+ /// Default value is infinite.
+ ///
+ public UInt64 MetalCompileTimeout;
+ }
+}