unity-game-engineopengl-esandroid-unity-plugin

How to call GL.IssuePlugInEvent in Unity3d and pass parameters to the plugin side in C


I'm trying to write a plugin for Unity that passes information between the native side of android (but same may apply to any other dll or so library) and the unity side. The information I want to share is OpenGL related. On Unity docs it's specified that everything that has to run on the rendering thread must be called through The GL.IssuePlugInEvent function. This function though is quite strict on the parameters: it needs a to call a function with a specific signature:

Callback must be a native function of "void UNITY_INTERFACE_API UnityRenderingEvent(int eventId)" signature

and has only the additional parameter eventId.

How can I then pass back on the unity side information from the so library?


Solution

  • The Unity examples for creating a plugin and using IssuePluginEvent cover the case where you want/need to call directly a C function, and this function accepts only an eventId as parameter. If the reader comes from a C\C++ background and is not familiar with C#, it may be misleading. In fact, you can actually call a C# function with this simple trick, and inside that function call your C functions passing multiple parameters. The steps are:

    1. get a function pointer for a C# function (notice that the function will be static)
    2. pass that function pointer to GL.IssuePluginEvent
    3. inside your static C# function, based on the case of eventId, call the appropriate C function
        void Update()
        {
            GL.IssuePluginEvent(RenderThreadHandlePtr, GL_INIT_EVENT); // example
        }
    
        /// <summary> Renders the event delegate described by eventID. </summary>
        /// <param name="eventID"> Identifier for the event.</param>
        private delegate void RenderEventDelegate(int eventID);
        /// <summary> Handle of the render thread. </summary>
        private static RenderEventDelegate RenderThreadHandle = new RenderEventDelegate(RunOnRenderThread);
        /// <summary> The render thread handle pointer. </summary>
        public static IntPtr RenderThreadHandlePtr = Marshal.GetFunctionPointerForDelegate(RenderThreadHandle);
    
        public const int GL_INIT_EVENT = 0x0001;
        public const int GL_DRAW_EVENT = 0x0002;
    
        /// <summary> Executes the 'on render thread' operation. </summary>
        /// <param name="eventID"> Identifier for the event.</param>
        [MonoPInvokeCallback(typeof(RenderEventDelegate))]
        private static void RunOnRenderThread(int eventID)
        {
            switch (eventID)
            {
                case GL_INIT_EVENT:
                    glInit(par1, par2, par3);  // C function with 3 parameters 
                    break;
                case GL_DRAW_EVENT:
                    glStep();
                    GL.InvalidateState();
                    break;
            }
        }
    
        [DllImport("hello-jni")]
        private static extern void glInit(int par1, int par2, int par3);
    
        [DllImport("hello-jni")]
        private static extern void glStep();