Search Unity

Unity Native Plug-in Interface with OpenGL/Cuda Interop - GL_INVALID_VALUE

Discussion in 'General Graphics' started by MasterOfTheMachineSpirit, Jan 16, 2020.

  1. MasterOfTheMachineSpirit

    MasterOfTheMachineSpirit

    Joined:
    Aug 26, 2019
    Posts:
    1
    Hello,

    I have a Unity application that uses the native plug-in interface to a C++ dll that reads h265 bit-streams from disk and decodes them using FFmpeg into NV12 format.
    After the frames are decoded they are sent to a Cuda kernel that does some image processing and converts the frames to YUV420p.
    The YUV frames are then sent back to OpenGL which attempts to render the frames on a Unity texture2D that is passed into the dll via GetNativeTexturePtr().

    The problem is that I am getting an openGL- GL_INVALID_VALUE -when attempting to update the texture using glTexSubImage2D(). I wonder if it could be a format issue of trying to render a YUV frame as an RGB? From my experience I should still be able to render and see something even though its corrupted.

    Here is the C# code followed by the C++ code:

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Runtime.InteropServices;
    5. using UnityEngine;
    6.  
    7. public class useNativeRenderPlugin : MonoBehaviour
    8. {
    9.     private Texture2D tex;
    10.     private Material mater;
    11.  
    12.     [DllImport("UnityCppDll")]
    13.     private static extern  IntPtr InvokeRenderCallBack();
    14.  
    15.     [DllImport("UnityCppDll")]
    16.     private static extern void SetTextureFromUnity(IntPtr unityTexture);
    17.  
    18.     IEnumerator Start()
    19.     {
    20.  
    21.         tex = new Texture2D(1920, 1080, TextureFormat.RGBA32, false);
    22.         mater = GetComponent<Renderer>().material;
    23.         mater.mainTexture = tex;
    24.         float offset = (float)-0.0047;
    25.         mater.shader = Shader.Find("Unlit/Texture");
    26.         mater.SetTextureOffset("_MainTex", new Vector2(offset, 0));
    27.         mater.mainTextureScale = new Vector2(1, -1);
    28.  
    29.         SetTextureFromUnity(tex.GetNativeTexturePtr());
    30.         yield return StartCoroutine("CallPluginAtEndOfFrames");
    31.  
    32.     }
    33.  
    34.     private IEnumerator CallPluginAtEndOfFrames()
    35.     {
    36.         Debug.Log("CallPluginAtEndOfFrames");
    37.  
    38.         while (true)
    39.         {
    40.             yield return new WaitForEndOfFrame(); // Wait till end of frame to render
    41.  
    42.             GL.IssuePluginEvent(InvokeRenderCallBack(), 1);
    43.         }
    44.  
    45.     }
    46.  
    47. }
    C++ dll code:

    Code (CSharp):
    1. //C++ CODE
    2.  
    3.         // Saving pointer to Unity texture2D.
    4.     void unityAdapter::setUnityTexture(void* unityTextureHandle) {
    5.         textureHandle = (GLuint)(size_t)unityTextureHandle;
    6.     }
    7.  
    8. /* ... */
    9.    
    10.         // Create PBO pixel buffer for copying frame data between Cuda and OpenGL texture.
    11.         // Frame (NV12) width = 1920 x height = 1080
    12.     glGenBuffers(1, &bufferPBO); // Generate unique buffer ID.
    13.     glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bufferPBO);
    14.     glBufferData(GL_PIXEL_UNPACK_BUFFER, (parameters.width * parameters.height *4), NULL, GL_DYNAMIC_COPY);
    15.     glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
    16.  
    17. /* ... */
    18.  
    19.  
    20.         // Register PBO with cuda.
    21.     if(cuRetVal != (cuRetVal = cudaGraphicsGLRegisterBuffer(&cudaGfxResources, bufferPBO, cudaGraphicsMapFlagsNone))) {
    22.         sprintf_s(msg, "**** cudaGraphicsGLRegisterBuffer return value: %d", retVal);
    23.         OutputDebugStringA(msg);
    24.     }
    25.    
    26.         // Map OpenGL resources for access from Cuda.
    27.     if (cudaSuccess != (retEr = cudaGraphicsMapResources(1, &cudaGfxResources, 0))) {
    28.         sprintf_s(msg, "*** cudaGraphicsMapResources retEr: %d", retEr);
    29.         OutputDebugStringA(msg);
    30.     }
    31.  
    32.     unsigned char framePtr = NULL;
    33.    
    34.         // Get a pointer to access mapped graphics resource.
    35.     if (cudaSuccess != (retEr = cudaGraphicsResourceGetMappedPointer((void**)&framePtr, &frameSize, cudaGfxResources))) {
    36.         sprintf_s(msg, "*** cudaGraphicsResourceGetMappedPointer retEr: %d", retEr);
    37.         OutputDebugStringA(msg);
    38.     }
    39.    
    40.     /* CUDA processing */
    41.    
    42.         // Get processed frame (YUV420p) and copy it to mapped OpenGL object.
    43.     if (cudaSuccess != (retEr = cudaMemcpy(framePtr, viewin[id].d_res, width_[0] * height_[0] * 3 / 2 * sizeof(short), cudaMemcpyDeviceToDevice ))) {
    44.         sprintf_s(msg, "*** cudaMemcpy retEr: %d", retEr);
    45.         OutputDebugStringA(msg);
    46.  
    47.     }
    48.         // Unmap resource to allow OpenGL access.
    49.     if (cudaSuccess != (retEr = cudaGraphicsUnmapResources(1, &cudaGfxResources, 0))) {
    50.         sprintf_s(msg, "*** cudaGraphicsUnmapResources retEr: %d", retEr);
    51.         OutputDebugStringA(msg);
    52.     }
    53.    
    54. /* ... */
    55.  
    56.         // Bind texture.
    57.     glGenTextures(1, &textureHandle);
    58.     glBindTexture(GL_TEXTURE_2D, textureHandle);
    59.    
    60.    
    61.         // Update texture - here is where it fails with GL_INVALID_VALUE.
    62.     glTexSubImage2D(GL_TEXTURE_2D,
    63.         0,
    64.         0,
    65.         0,
    66.         parameters.width,
    67.         parameters.height,
    68.         GL_RGBA,
    69.         GL_UNSIGNED_BYTE,
    70.         NULL);
    I appreciate any help!