Pass a RenderTexture to a plugin with zero copies

I have camera that renders to a RenderTexture. I would like to pass the contents of the RenderTexture to a native plugin. From the Unity’s native plugin example, a native plugin can only handle ID3D11Texture2D pointers which correspond to Unity’s Texture2D.GetNativeTexturePtr objects. Therefore, I have a functional version whereby the RenderTexture’s output is first copied to a Texture2D with ReadPixels:

    private IEnumerator DoEveryFrame()
    {
        //Wait for graphics to render
        yield return new WaitForEndOfFrame();

        // Remember current render textures
        RenderTexture currentActiveRT = RenderTexture.active;
        RenderTexture currentCamRT = cam.targetTexture;

        // Force rendering of the camera to my render texture
        cam.targetTexture = rt;
        cam.Render(); // 2nd Render seems to be necessary, but why??
        cam.targetTexture = currentCamRT;

        // Get a copy of the rendered data
        RenderTexture.active = rt;
        screenShot.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
        screenShot.Apply(); // hits perf significantly but needed otherwise actual copy does not occur
        
        // Restorie previously assigned render texture
        RenderTexture.active = currentActiveRT; 
        //Destroy(rt);

	    // Issue a plugin event with arbitrary integer identifier.
   	    // The plugin can distinguish between different
	    // things it needs to do based on this ID.
	    // For our simple plugin, it does not matter which ID we pass here.
	    GL.IssuePluginEvent (200); 


    }

Unfortunately, this method of using ReadPixels() and then Apply() significantly hurts performance. I don’t actually need the contents of RenderTexture on the CPU. How can I accomplish either of the following:

  1. [Preferred] Pass a valid reference to the RenderTexture directly to the native plugin without any data copying. This would be ideal. However, using RenderTexture.GetNativeTexturePtr resulted in all-black texture as seen by native plugin.
  2. Make a GPU-to-GPU copy of Render Texture to Texture2D. A copy is still involved, but at least it is not crossing the bus.

My second minor question is why do I need to perform a second Camera.Render()? Why doesn’t this work:

RenterTexture.active = cam.targetTexture;
screenShot.ReadPixels(...);
screenShot.Apply();

This must be doable; I’m just missing the magic invocation… :slight_smile:

Did you try to switch to OpenGL (on Windows with -force-opengl). I can use the OpenGL texture in my native C++ plugin.

At the moment I am struggling with Android. Same code as on Windows but black texture as well (no OpenGL errors). Maybe the Direct3D and Android OpenGL ES 2.0 are somehow related? Did you find a solution yet?

If you want to grab screen contents I think you can do this:

RenterTexture.active = null;
screenShot.ReadPixels(...);
screenShot.Apply();

Because what you’re doing right now is rendering to rt first and then grabbing, when you can grab from screen directly.