简体   繁体   English

OpenGL ES 2.0 - 如何有效地将纹理复制到帧缓冲区

[英]OpenGL ES 2.0 - How to efficiently copy a Texture into Frame Buffer

In short - I have an OpenGL texture which I need to copy into a FBO or another texture in the most efficient way possible under OpenGL ES 2.0. 简而言之 - 我有一个OpenGL纹理,我需要在OpenGL ES 2.0下以最有效的方式复制到FBO或其他纹理中。

At the moment I'm simply drawing the first texture into an FBO. 目前我只是将第一个纹理绘制到FBO中。

Is there a more efficient way? 有更有效的方法吗? Eg some sort of pixel copy that doesn't involve pulling the pixel data back to RAM and then buffering over to another texture - in ES 2.0 profile. 例如某种像素复制,不涉及将像素数据拉回RAM然后缓冲到另一个纹理 - 在ES 2.0配置文件中。

To give you context - this is video rendering related: 为您提供上下文 - 这与视频呈现相关:

I have an OpenGL texture being buffered with video frame data from LibVLC, but due to timing issues between my app redraw rate and the decoder refresh rate, its possible that the OpenGL texture has no new frame to update & very oddly if I were to draw the texture to the screen without a frame to update - instead of it containing the previous frame's data, it draws some weird image of its own ( it looks like a space invader ?? ) - hence why I need to 'cache' the previous frame's content. 我有一个OpenGL纹理被LibVLC的视频帧数据缓冲,但是由于我的应用重绘率和解码器刷新率之间存在时序问题,因此OpenGL纹理可能没有新的帧要更新,而且如果我要绘制,则很奇怪屏幕上的纹理而无需更新框架-它不包含前一帧的数据,而是绘制了自己的一些奇怪的图像(看起来像是空间入侵者??)-因此,为什么我需要“缓存”前一帧的图像内容。

Specifically, this is an OpenGL texture, used to create an Android SurfaceTexture, which I have to call updateTexImage and releaseTexImage manually to either update the Texture's content and then to mark that I'm done with the SurfaceTexture's content once I've drawn it. 具体来说,这是一个OpenGL纹理,用于创建Android SurfaceTexture,我必须手动调用updateTexImage和releaseTexImage来更新Texture的内容,然后标记我已经绘制了SurfaceTexture的内容。 If I don't release it then no new frames can be updated to it. 如果我不释放它,那么没有新的帧可以更新到它。 If I release it I can't redraw the same frame more than once. 如果我发布它,我不能多次重绘相同的帧。 Which has lead me to caching the texture once it's updated so the decoder is free to write to it & I still have the previous frame if when I come to draw again & there hasn't been an update yet. 这导致我在纹理更新后立即对其进行缓存,因此解码器可以自由地对其进行写入;如果再次绘制时还没有以前的帧,则我仍然拥有前一帧。

Thanks. 谢谢。

This solution is based on having worked out how to properly interface with the Android SurfaceTexture to avoid having to cache its contents altogether. 该解决方案基于已经研究出如何与Android SurfaceTexture正确接口以避免完全缓存其内容的方法。

If anyone wants to share an answer regarding efficient texture copies in OpenGL ES 2.0 please feel free - that would befit my original question. 如果有人想在OpenGL ES 2.0中分享关于高效纹理副本的答案,请随意 - 这将适合我原来的问题。

For anyone interested, this is what I did: 对于任何感兴趣的人,这就是我所做的:

My GLPaint class for rendering video on Android contains the SurfaceTexture instance, it's created from a JOGL OpenGL Texture ( using it's ID ) - This enables me to draw the texture as part of my GLPaint.paint function. 我的用于在Android上渲染视频的GLPaint类包含SurfaceTexture实例,它是从JOGL OpenGL Texture(使用其ID)创建的-这使我能够将纹理绘制为GLPaint.paint函数的一部分。

This GLPaint implements the onFrameAvailable method of the SurfaceTexture.OnFrameAvailableListener interface. 此GLPaint实现SurfaceTexture.OnFrameAvailableListener接口的onFrameAvailable方法。 I have a private boolean to flag when the first frame has been 'written' - this is needed to avoid releasing the SurfaceTexture prematurely. 当第一帧被“写入”时,我有一个专用的布尔值来标记-需要这样做以避免过早释放SurfaceTexture。

The class GUIThreadLock is my extension of a ReentrantLock - I extended it for additional debugging info and to make a static singleton. 类GUIThreadLock是我对ReentrantLock的扩展 - 我扩展了它以获得额外的调试信息并创建一个静态单例。 This lock in my 'one in - one out' controller for threads in my UI, ensuring only a single thread is active in my UI at a time ( usually just the main renderer looper ) but also handles getting the OpenGL context bound or unbound to the lock owner thread whenever one acquires and relinquishes the lock respectively. 我的“一进一出”控制器针对UI线程的锁定,确保一次仅在我的UI中激活一个线程(通常只是主渲染器循环程序),而且还可以处理将OpenGL上下文绑定到或未绑定到锁定所有者线程,无论何时分别获取和放弃锁定。

@Override
    public void onFrameAvailable( SurfaceTexture pSurfaceTexture )
    {
        try
        {
            GUIThreadLock.acquire();
            if( written )
            {
                pSurfaceTexture.releaseTexImage();
            }
            pSurfaceTexture.updateTexImage();
            written = true;
        }
        finally
        {
            GUIThreadLock.relinquish();
        }
    }

This means that when a new frame is ready, the SurfaceTexture releases the old one & updates to the new one - it is then buffered with the current frame for any point I wish to draw the video until the next frame is ready. 这意味着,当准备好新帧时,SurfaceTexture会释放旧帧并更新到新帧-然后将其与当前帧一起缓冲到我希望绘制视频的任何位置,直到下一帧准备好为止。 The GUIThreadLock protects the SurfaceTexture from updating the content while I may be drawing it but also acquires my GL Context so that the callback thread can actually perform the update here. GUIThreadLock可以保护SurfaceTexture在更新内容时不会更新内容,但也可以获取我的GL Context,以便回调线程实际上可以在此处执行更新。

My Redraw thread would also require the GUIThreadLock before it could draw my app - thus the GL context is protected and the relationship between frame updates and frame draws cemented. 我的Redraw线程在它可以绘制我的应用程序之前还需要GUIThreadLock - 因此GL上下文受到保护,帧更新和框架绘制之间的关系被粘合。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM