How can I get the RenderTexture OpenGL texture ID?

I need to render the output of the editor into an external Windows window(on Windows 7). We are using a projector plugged on the second screen and we need to render into fullscreen to test what we have done. Since Unity do not support fullscreen rendering into the editor, I am working on a plugin to render the output of the editor into a win32 window which will render the texture on every pixels of the second screen.

I am sharing the OpenGL context with the unity window and I need to get the texture ID of the screen RenderTexture to render this texture into an OpenGL quad in an another window.

I created an image effect to intercept the result of the rendering. And I’m using the source RenderTexture to get the native OpenGL ID of the texture. However, it does no seems to be an OpenGL texture id.

When I call glBindTexture(GL_TEXTURE_2D, textureIndex_) in C++, it returns this error: “Texture was previously created with a target that doesn’t match that of target.”. Which means that the ID returned by RenderTexture.GetNativeTextureID() is not a GL_TEXTURE_2D id. Considering that a RenderTexture contains a depth texture too, maybe it’s a Frame Buffer Object?

All call are done in the rendering thread since I’m using GL.IssuePluginEvent() to create/destroy/update my own OpenGL win32 window.

I’m wondering if I’m doing something wrong? Because the texture id returned by the RenderTexture do not seem to be an OpenGL texture ID.

Thanks for any help =).

Hi
From my short observation RenderTexture.GetNativeTextureID() return texture_2d id attached to FBO.
What I need is to get Frame Buffer Object ID but no idea how to obtain it.
Why FBO id is better:[PBO for async glGetTexImage, random slowdowns…][1]
[1]: PBO for async glGetTexImage, random slowdowns.. - OpenGL: Advanced Coding - Khronos Forums

I try to implement DMA transfer from FBO and display it on desktop - (WinXP).
I have tested both: glReadPixels,glGetTexImage and was not able to achieve good performance with DMA and glGetTexImage.
I am able to transfer data by glReadPixels (~10% CPU usage) but for that I need FBO id.
This is my short test program - maybe it helps a little (warning! I am FBO,PBO,VBO noob)

 int texture_id=0;
 //public Texture2D tex;
 public RenderTexture tex; 
 
 IEnumerator Start () {
 texture_id=tex.GetNativeTextureID();
 yield return StartCoroutine("CallPluginAtEndOfFrames");
 }
 
 private IEnumerator CallPluginAtEndOfFrames ()
 {
 while (true) {
 // Wait until all frame rendering is done
 yield return new WaitForEndOfFrame();
 
 // Set time for the plugin
 SetTimeFromUnity (Time.timeSinceLevelLoad);
 
 // 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 (texture_id);
 }
 }


Plugin code
-----------

    extern "C" void EXPORT_API BlitTexture(int textureID) 
{

        //this is called from issue plubin event
 static int index = 0;
 int nextIndex = 0;                  // pbo index used for next frame

 static bool b=0;
 int textureWidth,textureHeight=512;

 if (b==0)
 {
 // get pointers to GL functions
 glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB");
 glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB");
 glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB");
 glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)wglGetProcAddress("glBufferSubDataARB");
 glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB");
 glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)wglGetProcAddress("glGetBufferParameterivARB");
 glMapBufferARB = (PFNGLMAPBUFFERARBPROC)wglGetProcAddress("glMapBufferARB");
 glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)wglGetProcAddress("glUnmapBufferARB");
 glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)wglGetProcAddress("glBindFramebufferEXT");


 // create 2 pixel buffer objects, you need to delete them when program exits.
 // glBufferDataARB with NULL pointer reserves only memory space.
 glGenBuffersARB(PBO_COUNT, pboIds);
 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[0]);
 glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_READ_ARB);
 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[1]);
 glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_READ_ARB);

 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);

 b=1;

 freopen("debug.txt", "a", stdout);
 printf("SetTexture id:%d

" ,textureID);
printf("PBO ID:%d %d
" ,pboIds[0],pboIds[1]);

 }

 BITMAPINFOHEADER bhi;
 bhi.biSize=sizeof(BITMAPINFOHEADER);
 bhi.biWidth=512;
 bhi.biHeight=512;
 bhi.biPlanes=1;
 bhi.biBitCount=32;
 bhi.biCompression = BI_RGB;
 bhi.biSizeImage=bhi.biWidth*bhi.biHeight*4;
 bhi.biClrUsed=0;
 bhi.biClrImportant=0;
 bhi.biXPelsPerMeter=1000;
 bhi.biXPelsPerMeter=1000;

 // increment current index first then get the next index
 // "index" is used to read pixels from a framebuffer to a PBO
 // "nextIndex" is used to process pixels in the other PBO
 index = (index + 1) % 2;
 nextIndex = (index + 1) % 2;


 //glReadBuffer(textureID);
 //glBindTexture(GL_TEXTURE_2D, textureID);


 // Use offset instead of pointer.
 // OpenGL should perform asynch DMA transfer, so glReadPixels() will return immediately.

 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 1); //<-how to get this id from unity???
 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);

 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);
 glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, PIXEL_FORMAT, GL_UNSIGNED_BYTE, 0);
 //glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);

 // map the PBO that contain framebuffer pixels before processing it
 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[nextIndex]);
 GLubyte* src = (GLubyte*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
 if(src )
 {
 HDC dc=GetDC(0);
 SetDIBitsToDevice(dc,0,0,512,512,0,0,0,512,src,(BITMAPINFO*)&bhi,DIB_RGB_COLORS);
 ReleaseDC(0,dc);

 glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);     // release pointer to the mapped buffer
 }
 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);

}

A solution is to issue the plugin in the OnPostRender of the camera that renders to your RenderTexture. Then you don’t need to call

 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 1);

as the render texture is already bound.

Alternativly you can set it from Unity with RenderTexture.active before you issue the plugin

Example for displaying the unity camera view into an external window (for both OSX and Windows) , you could check : Render To External Window - YouTube .
Unfortunately , it has been declined (without explanation) by the unity asset store team .

Have you get your issue solved?
@G-Mika