Marshalling Interop Output From Maxine

so I’m trying to wrap the Maxine libraries from C# to make use of the expression feature

I’ve tested all samples and they work just fine and my code seems to load and run just fine. I’ve confirmed with a reverse transfer that my image data appears to be flowing through correctly so I’m assuming the library is seeing my images and running

I’m just stuck on reading the output data out at the end. no matter how I implement my marshalling code, the data keeps reading zero. I’ve tried several marshalling methods so at this point I can’t tell if it’s my interop going wrong or if I’m perhaps missing something about how I’m using the library

methods where I run the library

        public static bool Init(string rootDir, Vector2 cameraDims)
        {
            if (!TestResult(NvARAPI.NvAR_Create("FaceExpressions", out _featureHandle),
                "during creation")) return false;

            string path = rootDir + MODEL_DIR;
            StringBuilder boxedPath = new StringBuilder(path);
            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetString(FeatureHandle, NvARParameterSelectors.Config.ModelDir, boxedPath),
                "while setting model directory")) return false;

            ////optional? only used for streaming textures from cpu to gpu in NvCVImage?
            //_cudaStream = IntPtr.Zero;
            //if (!TestResult(NvARAPI.NvAR_SetCudaStream(FeatureHandle, NvARParameterSelectors.Config.CUDAStream, CudaStream),
            //    "while setting cuda stream")) return false;

            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetU32(FeatureHandle, NvARParameterSelectors.Config.Temporal, TEMPORAL),
                "while setting temporal mode")) return false;

            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetU32(FeatureHandle, NvARParameterSelectors.Config.Expression.PoseMode, POSE_MODE),
                "while setting pose mode")) return false;

            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetU32(FeatureHandle, NvARParameterSelectors.Config.Mode, MODE),
                "while setting mode")) return false;

            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetU32(FeatureHandle, NvARParameterSelectors.Config.Expression.EnableCheekPuff, ENABLE_CHEEK_PUFF),
                "while setting cheek puff")) return false;

            if (!TestResult(FeatureHandle, NvARAPI.NvAR_Load(FeatureHandle),
                "while loading")) return false;

            _boundingBoxes = new BoundingBoxes(25);
            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetObject(FeatureHandle, NvARParameterSelectors.Output.BoundingBoxes, BoundingBoxes.Pointer, (ulong)Marshal.SizeOf(typeof(NvAR_BBoxes))),
                "while setting bounding boxes")) return false;

            uint landmarkCount;
            if (!TestResult(FeatureHandle, NvARAPI.NvAR_GetU32(FeatureHandle, NvARParameterSelectors.Config.Landmarks_Size, out landmarkCount),
                "while getting landmark count")) return false;

            //const int landmarkCount = 126;

                _landmarks = new Landmarks((int)landmarkCount);
            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetObject(FeatureHandle, NvARParameterSelectors.Output.Landmarks, Landmarks.Pointer, (ulong)Marshal.SizeOf(typeof(NvAR_Point2f))),
                "while setting landmarks")) return false;

            _landmarkConfidences = new float[landmarkCount];
            //_confidencePin = GCHandle.Alloc(_landmarkConfidences, GCHandleType.Pinned);
            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetF32Array(FeatureHandle, NvARParameterSelectors.Output.LandmarksConfidence, _landmarkConfidences, landmarkCount),
                "while setting landmarks confidence")) return false;

            uint expressionCount;
            if (!TestResult(FeatureHandle, NvARAPI.NvAR_GetU32(FeatureHandle, NvARParameterSelectors.Config.ExpressionCount, out expressionCount),
                "while getting expression count")) return false;

            _expressionCoefficients = new float[expressionCount];
            //_coefficientPin = GCHandle.Alloc(_expressionCoefficients, GCHandleType.Pinned);
            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetF32Array(FeatureHandle, NvARParameterSelectors.Output.ExpressionCoefficients, _expressionCoefficients, expressionCount),
                "while setting expression coefficient")) return false;

            //for testing image data flow
            //_outputImgCPU = new NvCVImage();
            //if (!TestResult(FeatureHandle, NvCVImageAPI.NvCVImage_Alloc(ref _outputImgCPU, (uint)cameraDims.X, (uint)cameraDims.Y, NvCVImagePixelFormat.NVCV_BGRA, NvCVImageComponentType.NVCV_U8, NvCVLayout.NVCV_CHUNKY, NvCVMemSpace.NVCV_CPU, 1),
            //    "while creating output image object")) return false;

            _tempImg = new NvCVImage();
            if (!TestResult(FeatureHandle, NvCVImageAPI.NvCVImage_Alloc(ref _tempImg, (uint)cameraDims.X, (uint)cameraDims.Y, NvCVImagePixelFormat.NVCV_BGRA, NvCVImageComponentType.NVCV_U8, NvCVLayout.NVCV_CHUNKY, NvCVMemSpace.NVCV_GPU, 1),
                "while creating transfer image object")) return false;

            _inputImgGPU = new NvCVImage();
            if (!TestResult(FeatureHandle, NvCVImageAPI.NvCVImage_Alloc(ref _inputImgGPU, (uint)cameraDims.X, (uint)cameraDims.Y, NvCVImagePixelFormat.NVCV_BGR, NvCVImageComponentType.NVCV_U8, NvCVLayout.NVCV_CHUNKY, NvCVMemSpace.NVCV_GPU, 1),
                "while creating input image object")) return false;

            long sizeOfImgGPU = (int)Marshal.SizeOf(InputImgGPU);
            _inputImgGPUPtr = Marshal.AllocCoTaskMem((int)sizeOfImgGPU);
            Marshal.StructureToPtr(InputImgGPU, InputImgGPUPtr, false);
            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetObject(FeatureHandle, NvARParameterSelectors.Input.Image, InputImgGPUPtr, (ulong)sizeOfImgGPU),
                "while setting input image object")) return false;

            _cameraIntrinsics = new float[]
            {
                cameraDims.Y,
                cameraDims.X / 2.0f,
                cameraDims.Y / 2.0f
            };
            //_intrinsicsPin = GCHandle.Alloc(_cameraIntrinsics, GCHandleType.Pinned);
            if (!TestResult(FeatureHandle, NvARAPI.NvAR_SetF32Array(FeatureHandle, NvARParameterSelectors.Input.Expression.CameraIntrinsicParams, _cameraIntrinsics, (uint)CameraIntrinsics.Length),
                    "while setting camera intrinsics")) return false;

            //don't need a rotation transform
            //if (!TestResult(NvARAPI.NvAR_SetObject(FeatureHandle, NvARParameterSelectors.Output.Pose, ),
            //    "while setting output pose")) return false;

            //don't need a translation transform
            //if (!TestResult(NvARAPI.NvAR_SetObject(FeatureHandle, NvARParameterSelectors.Output.Expression.PoseTranslation, ),
            //    "while setting pose translation")) return false;

            return true;
        }
        public static bool Run(IntPtr pixelBuffer, Vector2 imageDims, int stride)
        {
            IntPtr cuda = IntPtr.Zero;

            NvCVImage inputImgCPU = new NvCVImage();
            NVWrapperForData(pixelBuffer, imageDims, 4, 1, NvCVImagePixelFormat.NVCV_BGRA, NvCVImageComponentType.NVCV_U8, NvCVLayout.NVCV_CHUNKY, NvCVMemSpace.NVCV_CPU, ref inputImgCPU);

            if (!TestResult(NvCVImageAPI.NvCVImage_Transfer(inputImgCPU, InputImgGPU, 1.0f, cuda, TempImg),
                "during input transfer")) return false;

            if (!TestResult(NvARAPI.NvAR_Run(FeatureHandle),
                "when running")) return false;

            /* //for testing image data flow
            if (!TestResult(NvCVImageAPI.NvCVImage_Transfer(InputImgGPU, OutputImgCPU, 1.0f, cuda, TempImg),
                "during output transfer")) return false;

            int byteCount = (int)OutputImgCPU.Width * (int)OutputImgCPU.Height * (int)OutputImgCPU.NumComponents * (int)OutputImgCPU.ComponentBytes;
            byte[] outputArray = new byte[byteCount];
            Marshal.Copy(OutputImgCPU.Pixels, outputArray, 0, byteCount);
            */

            //requesting output data causes crashes?
            //float[] landmarkConfidences;
            //uint landmarkCount;
            //if (!TestResult(FeatureHandle, NvARAPI.NvAR_GetF32Array(FeatureHandle, NvARParameterSelectors.Output.LandmarksConfidence, out landmarkConfidences, out landmarkCount),
            //    "while getting landmarks confidence")) return false;

            //float[] expressionCoefficients;
            //uint expressionCount;
            //if (!TestResult(FeatureHandle, NvARAPI.NvAR_GetF32Array(FeatureHandle, NvARParameterSelectors.Output.ExpressionCoefficients, out expressionCoefficients, out expressionCount),
            //    "while getting expression coefficient")) return false;

            //calibrate weights

            //work with output bounding boxes
            NvAR_Rect[] boxes = BoundingBoxes.Get();
            NvAR_Point2f[] landmarks = Landmarks.Get();

            foreach (NvAR_Rect box in boxes)
            {
                Log.Record("Box detected, x: " + box.x.ToString() + " y: " + box.y.ToString() + " width: " + box.width.ToString() + " height: " + box.height.ToString());
            }
            foreach (NvAR_Point2f landmark in landmarks)
            {
                Log.Record("Landmark detected, x: " + landmark.x.ToString() + " y: " + landmark.y.ToString());
            }
            foreach (float confidence in LandmarkConfidences)
            {
                Log.Record("Landmark confidence: " + confidence.ToString());
            }
            foreach (float coefficient in ExpressionCoefficients)
            {
                Log.Record("Expression coefficient: " + coefficient.ToString());
            }

            return true;
        }

my struct definitions

    [StructLayout(LayoutKind.Sequential)]
    public struct NvAR_BBoxes
    {
        public IntPtr boxes;

        [MarshalAs(UnmanagedType.U1)]
        public byte num_boxes;

        [MarshalAs(UnmanagedType.U1)]
        public byte max_boxes;


        public NvAR_BBoxes()
        {
            boxes = IntPtr.Zero;
            num_boxes = 0;
            max_boxes = 0;
        }
        public unsafe NvAR_BBoxes(IntPtr boxes, byte num_boxes, byte max_boxes)
        {
            this.boxes = boxes;
            this.num_boxes = num_boxes;
            this.max_boxes = max_boxes;
        }

    }
    [StructLayout(LayoutKind.Sequential)]
    public struct NvAR_Rect
    {
        [MarshalAs(UnmanagedType.R4)]
        public float x;

        [MarshalAs(UnmanagedType.R4)]
        public float y;

        [MarshalAs(UnmanagedType.R4)]
        public float width;

        [MarshalAs(UnmanagedType.R4)]
        public float height;


        public NvAR_Rect()
        {
            x = 0;
            y = 0;
            width = 0;
            height = 0;
        }

        public NvAR_Rect(float x, float y, float width, float height)
        {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct NvAR_Point2f
    {
        [MarshalAs(UnmanagedType.R4)]
        public float x;

        [MarshalAs(UnmanagedType.R4)]
        public float y;



        public NvAR_Point2f()
        {
            x = 0;
            y = 0;
        }

        public NvAR_Point2f(float x, float y)
        {
            this.x = x;
            this.y = y;
        }
    }

my current marshalling method is copying to and from IntPtrs, like so

    public class BoundingBoxes : IDisposable
    {

        private IntPtr _pointer;
        private int _length;


        public IntPtr Pointer
        {
            get { return _pointer; }
        }
        private int Length
        {
            get { return _length; }
        }


        public BoundingBoxes(int length)
        {
            _length = length;
            NvAR_Rect[] initial = new NvAR_Rect[Length];
            int size = Marshal.SizeOf(typeof(NvAR_Rect));
            IntPtr boxesPtr = Marshal.AllocCoTaskMem(size * Length);

            long baseAddress = boxesPtr.ToInt64();
            for (int i = 0; i < Length; i++)
            {
                IntPtr toInit = new IntPtr(baseAddress + (i * size));
                Marshal.StructureToPtr(initial[i], toInit, false);
            }

            NvAR_BBoxes boxesStruct = new NvAR_BBoxes(boxesPtr, 0, (byte)length);
            _pointer = Marshal.AllocCoTaskMem(size + (Marshal.SizeOf(typeof(byte)) * 2));
            Marshal.StructureToPtr(boxesStruct, _pointer, false);
        }


        public NvAR_Rect[] Get()
        {
            NvAR_BBoxes boxesStruct = Marshal.PtrToStructure<NvAR_BBoxes>(Pointer);

            NvAR_Rect[] result = new NvAR_Rect[Length];
            int size = Marshal.SizeOf(typeof(NvAR_Rect));
            long baseAddress = boxesStruct.boxes.ToInt64();
            for (int i = 0; i < Length; i++)
            {
                IntPtr toRetrieve = new IntPtr(baseAddress + (i * size));
                NvAR_Rect retrieved = Marshal.PtrToStructure<NvAR_Rect>(toRetrieve);
                result[i] = retrieved;
            }

            return result;
        }


        public void Dispose()
        {
            if (Pointer != IntPtr.Zero)
                Marshal.FreeCoTaskMem(Pointer);
        }
    }
    public class Landmarks : IDisposable
    {

        private IntPtr _pointer;
        private int _length;


        public IntPtr Pointer
        {
            get { return _pointer; }
        }
        private int Length
        {
            get { return _length; }
        }


        public Landmarks(int length)
        {
            _length = length;
            NvAR_Point2f[] initial = new NvAR_Point2f[Length];
            int size = Marshal.SizeOf(typeof(NvAR_Point2f));
            _pointer = Marshal.AllocCoTaskMem(size * Length);

            long baseAddress = Pointer.ToInt64();
            for (int i = 0; i < Length; i++)
            {
                IntPtr toInit = new IntPtr(baseAddress + (i * size));
                Marshal.StructureToPtr(initial[i], toInit, false);
            }
        }


        public NvAR_Point2f[] Get()
        {
            NvAR_Point2f[] result = new NvAR_Point2f[Length];
            int size = Marshal.SizeOf(typeof(NvAR_Point2f));
            long baseAddress = Pointer.ToInt64();

            for (int i = 0; i < Length; i++)
            {
                IntPtr toRetrieve = new IntPtr(baseAddress + (i * size));
                NvAR_Point2f retrieved = Marshal.PtrToStructure<NvAR_Point2f>(toRetrieve);
                result[i] = retrieved;
            }

            return result;
        }


        public void Dispose()
        {
            if (Pointer != IntPtr.Zero)
                Marshal.FreeCoTaskMem(Pointer);
        }

    }

and my API prototype class

    public class NvARAPI
    {
        private const string NvARLib = API.DEPENDENCY_DIR + "nvARPose.dll";

        /// <summary>
        /// This function sets the value of the specified 32-bit unsigned integer parameter for the specified feature instance to the <para>val</para> parameter.
        /// </summary>
        /// <param name="feature">The handle to the feature instance for which you want to set the specified 32-bit unsigned integer parameter. </param>
        /// <param name="paramName">The selector of the effect parameter to configure.</param>
        /// <param name="val">The value to be assigned to the selected effect parameter.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_PARAMETER
        /// NVCV_ERR_SELECTOR
        /// NVCV_ERR_GENERAL
        /// NVCV_ERR_MISMATCH
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern NvCVStatus NvAR_SetU32(IntPtr feature, string paramName, uint val);


        /// <summary>
        /// This function loads the specified feature instance and validates any configuration properties that were set for the feature instance.
        /// </summary>
        /// <param name="feature">The handle to the feature instance to load.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_MISSINGINPUT
        /// NVCV_ERR_FEATURENOTFOUND
        /// NVCV_ERR_INITIALIZATION
        /// NVCV_ERR_UNIMPLEMENTED
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern NvCVStatus NvAR_Load(IntPtr feature);


        /// <summary>
        /// This function validates the input/output properties that are set by the user, runs the specified feature instance with the input properties that were set for the instance, and writes the results to the output properties set for the instance. The input and output properties are set by the accessor functions.
        /// </summary>
        /// <param name="feature">The handle to the feature instance to be run.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_GENERAL
        /// NVCV_ERR_FEATURENOTFOUND
        /// NVCV_ERR_MEMORY
        /// NVCV_ERR_MISSINGINPUT
        /// NVCV_ERR_PARAMETER
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern NvCVStatus NvAR_Run(IntPtr feature);


        /// <summary>
        /// This function assigns the memory of the object that was specified by the ptr parameter to the specified object parameter for the specified feature instance.
        /// </summary>
        /// <param name="feature">The handle to the feature instance for which you want to set the specified object.</param>
        /// <param name="paramName">The selector of the effect parameter to configure.</param>
        /// <param name="ptr">A pointer to memory that was allocated to the objects that were defined in Structures.</param>
        /// <param name="typeSize">The size of the item to which the pointer points. If the size does not match, an NVCV_ERR_MISMATCH is returned.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_PARAMETER
        /// NVCV_ERR_SELECTOR
        /// NVCV_ERR_GENERAL
        /// NVCV_ERR_MISMATCH
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static unsafe extern NvCVStatus NvAR_SetObject(IntPtr feature, string paramName, IntPtr ptr, ulong typeSize);


        /// <summary>
        /// This function assigns the array of floating-point numbers that are defined by the vals parameter to the specified floating-point-array parameter for the specified feature instance.
        /// </summary>
        /// <param name="feature">The handle to the feature instance for which you want to set the specified float array.</param>
        /// <param name="paramName">The selector of the effect parameter to configure.</param>
        /// <param name="vals">An array of floating-point numbers to which the parameter will be set.</param>
        /// <param name="count">Currently unused. The number of elements in the array that is specified by the vals parameter.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_PARAMETER
        /// NVCV_ERR_SELECTOR
        /// NVCV_ERR_GENERAL
        /// NVCV_ERR_MISMATCH
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static unsafe extern NvCVStatus NvAR_SetF32Array(IntPtr feature, string paramName, [In, Out] float[] vals, uint count);


        /// <summary>
        /// This function gets the values in the specified floating-point array for the specified feature instance and writes the retrieved values to an array at the location that is specified by the vals parameter.
        /// </summary>
        /// <param name="feature">The handle to the feature instance for which you want to set the specified float array.</param>
        /// <param name="paramName">The selector of the effect parameter to configure.</param>
        /// <param name="vals">Pointer to an array of floating-point numbers where the retrieved values will be written.</param>
        /// <param name="count">Currently unused. The number of elements in the array that is specified by the vals parameter.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_PARAMETER
        /// NVCV_ERR_SELECTOR
        /// NVCV_ERR_MISSINGINPUT
        /// NVCV_ERR_GENERAL
        /// NVCV_ERR_MISMATCH
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern NvCVStatus NvAR_GetF32Array(IntPtr feature, string paramName, out float[] vals, out uint count);


        /// <summary>
        /// This function gets the value of the specified 32-bit signed integer parameter for the specified feature instance and writes the retrieved value to the location that is specified by the val parameter. 
        /// </summary>
        /// <param name="feature">The handle to the feature instance from which you get the specified 32-bit signed integer parameter. </param>
        /// <param name="paramName">The selector of the effect parameter to retrieve.</param>
        /// <param name="val">Pointer to the 32-bit signed integer where the retrieved value will be written.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_PARAMETER
        /// NVCV_ERR_SELECTOR
        /// NVCV_ERR_GENERAL
        /// NVCV_ERR_MISMATCH
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern NvCVStatus NvAR_GetU32(IntPtr feature, string paramName, out uint val);


        /// <summary>
        /// This function gets the value of the specified character string parameter for the specified feature instance and writes the retrieved string to the location that is specified by the str parameter.  
        /// </summary>
        /// <param name="feature">The handle to the feature instance from which you get the specified 32-bit signed integer parameter. </param>
        /// <param name="paramName">The selector of the effect parameter to retrieve.</param>
        /// <param name="val">The address where the requested character string pointer is stored.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_PARAMETER
        /// NVCV_ERR_SELECTOR
        /// NVCV_ERR_MISSINGINPUT
        /// NVCV_ERR_GENERAL
        /// NVCV_ERR_MISMATCH
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern NvCVStatus NvAR_GetString(IntPtr feature, string paramName, out string val);


        /// <summary>
        /// This function sets the value of the specified character string parameter for the specified feature instance to the str parameter. 
        /// </summary>
        /// <param name="feature">The handle to the feature instance for which you want to set the specified character string parameter.</param>
        /// <param name="paramName">The selector of the effect string to configure.</param>
        /// <param name="str">The value to be assigned to the selected effect string. NULL clears the selected string.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_PARAMETER
        /// NVCV_ERR_SELECTOR
        /// NVCV_ERR_GENERAL
        /// NVCV_ERR_MISMATCH
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        public static extern NvCVStatus NvAR_SetString(
            IntPtr feature,
            [MarshalAs(UnmanagedType.LPStr)] string paramName,
            StringBuilder str);


        /// <summary>
        /// Wrapper for cudaStreamCreate(), if it is desired to avoid linking with the cuda lib.
        /// </summary>
        /// <param name="stream">A place to store the newly allocated stream.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS if the operation was successful,
        /// NVCV_ERR_CUDA_VALUE if not.
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern NvCVStatus NvVFX_CudaStreamCreate(/*CUstream*/ out IntPtr stream);


        /// <summary>
        /// Wrapper for cudaStreamDestroy(), if it is desired to avoid linking with the cuda lib.
        /// </summary>
        /// <param name="stream">The stream to destroy.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS if the operation was successful,
        /// NVCV_ERR_CUDA_VALUE if not.
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern NvCVStatus NvVFX_CudaStreamDestroy(/*CUstream*/ IntPtr stream);


        /// <summary>
        /// This function sets the CUDA stream, in which the specified feature instance will run, to the parameter stream.
        /// </summary>
        /// <param name="feature">The handle to the feature instance that is returned for which you want to set the CUDA stream.</param>
        /// <param name="paramName">The selector of the effect parameter to configure.</param>
        /// <param name="stream">The CUDA stream in which to run the feature instance on the GPU.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_PARAMETER
        /// NVCV_ERR_SELECTOR
        /// NVCV_ERR_GENERAL
        /// NVCV_ERR_MISMATCH
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern NvCVStatus NvAR_SetCudaStream(IntPtr feature, string paramName, IntPtr stream);


        /// <summary>
        /// This function creates an instance of the specified feature type and writes a handle to the feature instance to the handle out parameter. 
        /// </summary>
        /// <param name="code">The selector code for the type of feature to be created.</param>
        /// <param name="feature">A handle to the newly created feature instance.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_FEATURENOTFOUND
        /// NVCV_ERR_INITIALIZATION
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern NvCVStatus NvAR_Create(string code, out IntPtr feature);


        /// <summary>
        /// This function releases the feature instance with the specified handle. Because handles are not reference counted, the handle is invalid after this function is called. 
        /// </summary>
        /// <param name="feature">The handle to the feature instance to be released.</param>
        /// <returns>
        /// NvCVStatus.
        /// NVCV_SUCCESS on success
        /// NVCV_ERR_FEATURENOTFOUND
        /// </returns>
        [DllImport(NvARLib, CallingConvention = CallingConvention.Cdecl)]
        public static extern void NvAR_Destroy(IntPtr feature);

    }

this is currently running but only outputting zero across the board

I’ve tried a number of things, including using the API’s Get functions to try to poll the output data structures at run time but that always results in crashes for me and I’m unclear if that’s even supported
I’ve also tried what other people are doing in some of the existing github projects to wrap the Maxine libraries but nobody’s wrapped the AR module yet and trying to transfer what they’ve done with the Audio/Video modules didn’t work for me

any indications if the problem is with how I’m using the library or with the interop would be great. I’ve tried enough things now at this point that I can’t be sure
it especially isn’t making sense to me because the SetF32Array should be even simpler, in that I expect default marshalling behavior to handle it perfectly but I still don’t get any output in those arrays