FacticiusVir / SharpVk

C# Bindings for the Vulkan API & SPIR-V
MIT License
147 stars 18 forks source link

`...Info` structures not unmarshaled. #49

Open Y-Less opened 5 years ago

Y-Less commented 5 years ago

This is mainly an issue for DebugUtilsMessengerCallbackData, which contains DebugUtilsObjectNameInfo[], and thus is transitively not unmarshalled for use in CreateDebugUtilsMessenger, I'm currently doing this:

using System;

namespace SharpVk.Multivendor
{
    public partial class DebugReportDelegate : IDisposable
    {
        private readonly SharpVk.Multivendor.DebugReportCallback callback_;
        private readonly System.Runtime.InteropServices.GCHandle gch_;

        internal DebugReportDelegate(System.Runtime.InteropServices.GCHandle gch, SharpVk.Multivendor.DebugReportCallback callback)
        {
            callback_ = callback;
            gch_ = gch;
        }

        public void Dispose()
        {
            callback_.Dispose();
            gch_.Free();
        }
    }

    public interface IDebugReportDelegate
    {
        bool DebugReportDelegate(SharpVk.Multivendor.DebugReportFlags flags, SharpVk.Multivendor.DebugReportObjectType objectType, ulong @object, HostSize location, int messageCode, string pLayerPrefix, string pMessage);
    }

    public partial class DebugUtilsDelegate : IDisposable
    {
        private readonly SharpVk.Multivendor.DebugUtilsMessenger callback_;
        private readonly System.Runtime.InteropServices.GCHandle gch_;

        internal DebugUtilsDelegate(System.Runtime.InteropServices.GCHandle gch, SharpVk.Multivendor.DebugUtilsMessenger callback)
        {
            callback_ = callback;
            gch_ = gch;
        }

        public void Dispose()
        {
            callback_.Dispose();
            gch_.Free();
        }
    }

    public interface IDebugUtilsDelegate
    {
        bool DebugUtilsDelegate(SharpVk.Multivendor.DebugUtilsMessageSeverityFlags messageSeverity, SharpVk.Multivendor.DebugUtilsMessageTypeFlags messageTypes, SharpVk.Multivendor.DebugUtilsMessengerCallbackData pCallbackDatas);
    }

    /// <summary>
    /// 
    /// </summary>
    public static class HLInstanceExtensions
    {
        /// <summary>
        /// Create a debug report callback object.
        /// </summary>
        /// <param name="extendedHandle">
        /// The Instance handle to extend.
        /// </param>
        /// <param name="flags">
        /// flags indicate which event(s) will cause this callback to be
        /// called. Flags are interpreted as bitmasks and multiple may be set.
        /// Bits which can be set include: + --
        /// </param>
        /// <param name="allocator">
        /// An optional AllocationCallbacks instance that controls host memory
        /// allocation.
        /// </param>
        public static SharpVk.Multivendor.DebugReportDelegate CreateDebugReportDelegate(this SharpVk.Instance extendedHandle, SharpVk.Multivendor.IDebugReportDelegate callback, SharpVk.Multivendor.DebugReportFlags? flags = default(SharpVk.Multivendor.DebugReportFlags?), SharpVk.AllocationCallbacks? allocator = default(SharpVk.AllocationCallbacks?))
        {
            System.Runtime.InteropServices.GCHandle gch = System.Runtime.InteropServices.GCHandle.Alloc(callback);
            try
            {
                SharpVk.Multivendor.DebugReportCallback result = extendedHandle.CreateDebugReportCallback(DebugReportDelegate, flags, System.Runtime.InteropServices.GCHandle.ToIntPtr(gch), allocator);
                return new SharpVk.Multivendor.DebugReportDelegate(gch, result);
            }
            catch
            {
                gch.Free();
                throw;
            }
        }

        private static readonly SharpVk.Multivendor.DebugReportCallbackDelegate DebugReportDelegate = DebugReport;

        private static Bool32 DebugReport(SharpVk.Multivendor.DebugReportFlags flags, SharpVk.Multivendor.DebugReportObjectType objectType, ulong @object, HostSize location, int messageCode, string pLayerPrefix, string pMessage, IntPtr pUserData)
        {
            if (pUserData == IntPtr.Zero)
            {
                return false;
            }
            System.Runtime.InteropServices.GCHandle gch = System.Runtime.InteropServices.GCHandle.FromIntPtr(pUserData);
            IDebugReportDelegate idrd = (IDebugReportDelegate)gch.Target;
            if (idrd == null)
            {
                return false;
            }

            return idrd.DebugReportDelegate(flags, objectType, @object, location, messageCode, pLayerPrefix, pMessage);
        }

        /// <summary>
        /// Create a debug utils messenger object.
        /// </summary>
        /// <param name="extendedHandle">
        /// The Instance handle to extend.
        /// </param>
        /// <param name="flags">
        /// flags indicate which event(s) will cause this callback to be
        /// called. Flags are interpreted as bitmasks and multiple may be set.
        /// Bits which can be set include: + --
        /// </param>
        /// <param name="allocator">
        /// An optional AllocationCallbacks instance that controls host memory
        /// allocation.
        /// </param>
        public static SharpVk.Multivendor.DebugUtilsDelegate CreateDebugUtilsDelegate(this SharpVk.Instance extendedHandle, SharpVk.Multivendor.DebugUtilsMessageSeverityFlags messageSeverity, SharpVk.Multivendor.DebugUtilsMessageTypeFlags messageType, SharpVk.Multivendor.IDebugUtilsDelegate callback, SharpVk.Multivendor.DebugUtilsMessengerCreateFlags? flags = default(SharpVk.Multivendor.DebugUtilsMessengerCreateFlags?), SharpVk.AllocationCallbacks? allocator = default(SharpVk.AllocationCallbacks?))
        {
            System.Runtime.InteropServices.GCHandle gch = System.Runtime.InteropServices.GCHandle.Alloc(callback);
            try
            {
                SharpVk.Multivendor.DebugUtilsMessenger result = extendedHandle.CreateDebugUtilsMessenger(messageSeverity, messageType, DebugUtilsDelegate, flags, System.Runtime.InteropServices.GCHandle.ToIntPtr(gch), allocator);
                return new SharpVk.Multivendor.DebugUtilsDelegate(gch, result);
            }
            catch
            {
                gch.Free();
                throw;
            }
        }

        private static readonly SharpVk.Multivendor.DebugUtilsMessengerCallbackDelegate DebugUtilsDelegate = DebugUtils;

        private unsafe static SharpVk.Multivendor.DebugUtilsLabel MarshalFrom(SharpVk.Interop.Multivendor.DebugUtilsLabel* pointer)
        {
            SharpVk.Multivendor.DebugUtilsLabel result = default(SharpVk.Multivendor.DebugUtilsLabel);
            result.LabelName = pointer->LabelName == null ? null : System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new IntPtr(pointer->LabelName));
            result.Color = (pointer->Color[0], pointer->Color[1], pointer->Color[2], pointer->Color[3]);
            return result;
        }

        private unsafe static SharpVk.Multivendor.DebugUtilsObjectNameInfo MarshalFrom(SharpVk.Interop.Multivendor.DebugUtilsObjectNameInfo* pointer)
        {
            SharpVk.Multivendor.DebugUtilsObjectNameInfo result = default(SharpVk.Multivendor.DebugUtilsObjectNameInfo);
            result.ObjectType = pointer->ObjectType;
            result.ObjectHandle = pointer->ObjectHandle;
            result.ObjectName = pointer->ObjectName == null ? null : System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new IntPtr(pointer->ObjectName));
            return result;
        }

        private unsafe static SharpVk.Multivendor.DebugUtilsMessengerCallbackData MarshalFrom(SharpVk.Interop.Multivendor.DebugUtilsMessengerCallbackData* pointer)
        {
            SharpVk.Multivendor.DebugUtilsMessengerCallbackData result = default(SharpVk.Multivendor.DebugUtilsMessengerCallbackData);
            result.Flags = pointer->Flags;
            result.MessageIdName = pointer->MessageIdName == null ? null : System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new IntPtr(pointer->MessageIdName));
            result.MessageIdNumber = pointer->MessageIdNumber;
            result.Message = pointer->Message == null ? null : System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new IntPtr(pointer->Message));

            if (pointer->QueueLabels == null)
            {
                result.QueueLabels = null;
            }
            else
            {
                result.QueueLabels = new DebugUtilsLabel[pointer->QueueLabelCount];
                for (int index = 0; index < (uint)(result.QueueLabels.Length); index++)
                {
                    result.QueueLabels[index] = MarshalFrom(&pointer->QueueLabels[index]);
                }
            }

            if (pointer->CommandBufLabels == null)
            {
                result.CommandBufLabels = null;
            }
            else
            {
                result.CommandBufLabels = new DebugUtilsLabel[pointer->CommandBufLabelCount];
                for (int index = 0; index < (uint)(result.CommandBufLabels.Length); index++)
                {
                    result.CommandBufLabels[index] = MarshalFrom(&pointer->CommandBufLabels[index]);
                }
            }

            if (pointer->Objects == null)
            {
                result.Objects = null;
            }
            else
            {
                result.Objects = new DebugUtilsObjectNameInfo[pointer->ObjectCount];
                for (int index = 0; index < (uint)(result.Objects.Length); index++)
                {
                    result.Objects[index] = MarshalFrom(&pointer->Objects[index]);
                }
            }

            return result;
        }

        private static unsafe Bool32 DebugUtils(SharpVk.Multivendor.DebugUtilsMessageSeverityFlags messageSeverity, SharpVk.Multivendor.DebugUtilsMessageTypeFlags messageTypes, IntPtr pCallbackData, IntPtr pUserData)
        {
            if (pUserData == IntPtr.Zero)
            {
                return false;
            }
            System.Runtime.InteropServices.GCHandle gch = System.Runtime.InteropServices.GCHandle.FromIntPtr(pUserData);
            IDebugUtilsDelegate idrd = (IDebugUtilsDelegate)gch.Target;
            if (idrd == null)
            {
                return false;
            }

            SharpVk.Multivendor.DebugUtilsMessengerCallbackData userData = MarshalFrom((SharpVk.Interop.Multivendor.DebugUtilsMessengerCallbackData*)pCallbackData.ToPointer());
            return idrd.DebugUtilsDelegate(messageSeverity, messageTypes, userData);
        }
    }
}

I tried to match the generated code style as much as possible, but without being able to use any of the internal HeapUtil methods.

FacticiusVir commented 5 years ago

The filter on "...Info" structs was likely to identify types used purely for input (e.g. CreateInfo types) which are/were not consistently identified in vk.xml; there's no handling for this case of structs as callback parameters. The current implementation of callbacks needs several improvements in any case, but the Debug Utils use case raises the priority a little.

Unless I can find a more intelligent filter to handle the input Info structs case, I'll find a subfilter for Info structs that are passed back out from the API in callback delegates.