zoukankan      html  css  js  c++  java
  • GPUImage源码解读之GPUImageFramebuffer

    简介

    OpenGL ES的FrameBuffer是渲染发生的地方,普通的2D图形的渲染默认发生在屏幕上;而三维的图形渲染则除了包括像素点的颜色,还有Depth Buffer,Stencil Buffer等其他空间。因此,FrameBuffer就是一个这些Buffer的一个集合。

    默认情况下,FrameBuffer存在于现存中,但是当需要进行多次渲染或者离屏渲染的时候,可以通过创建一个离屏的FrameBuffer进行渲染。当需要渲染3D效果时,除了创建frameBuffer以外,还需要创建相应的Render Buffer, Depth Buffer, Stencil Buffer,并且将它们attach到frameBuffer上;而当只需要渲染2D图形时,可以直接生成一个Texture,并且将FrameBuffer渲染的结果放入Texture中。

    生成一个FrameBuffer的代码:

    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    

    由于存在离屏渲染的情况,实际渲染开始之前,需要先激活目标FrameBuffer,而在渲染完成之后,需要将FrameBuffer绑定为0,回到默认的FrameBuffer,才能够显示在屏幕上:

    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    //Rendering Code
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    

    如果要渲染一个2D图像到一个Texture上,则还需要先生成一个Texture,并且将Texture绑定到FrameBuffer上。当使用FrameBuffer进行流的传递的时候,则可以使用这个Texture:

    glActiveTexture(GL_TEXTURE1);
        glGenTextures(1, &_texture);
        glBindTexture(GL_TEXTURE_2D, _texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        // This is necessary for non-power-of-two textures
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glBindTexture(GL_TEXTURE_2D, _texture);
                
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)_size.width, (int)_size.height, 0,GL_RGBA, GL_UNSIGNED_BYTE, 0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
    

    GPUImageFrameBuffer

    GPUImageFrameBuffer不只是简单的对OpenGL ES的FrameBuffer的对象化封装,而是一个对渲染对象的对象化封装。它生成的可以是一个带有Texture作为Attachment的FrameBuffer,也可以仅仅生成一个Texture作为渲染对象。它的主要功能有:

    • 生成渲染对象,FrameBuffer或者Texture,带的参数包括size和texture option,这两个参数主要是用于FrameBuffer的重用,GPUImageFramebufferCache中会介绍到:
    - (id)initWithSize:(CGSize)framebufferSize;
    - (id)initWithSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)fboTextureOptions onlyTexture:(BOOL)onlyGenerateTexture;
    - (id)initWithSize:(CGSize)framebufferSize overriddenTexture:(GLuint)inputTexture;
    
    • FrameBuffer的管理,在渲染的时候激活frameBuffer:
    - (void)activateFramebuffer;
    
    • FrameBuffer的引用计数。同样用于FrameBuffer的重用,GPUImageFramebufferCache会详细介绍:
    - (void)lock;
    - (void)unlock;
    - (void)clearAllLocks;
    - (void)disableReferenceCounting;
    - (void)enableReferenceCounting;
    
    • 从FrameBuffer中生成图片或者源数据:
    - (CGImageRef)newCGImageFromFramebufferContents;
    - (GLubyte *)byteBuffer;
    

    GPUImageFrameBuffer的引用计数

    由于GPUImageFrameBuffer需要重用,因此,当FrameBuffer的引用为0的时候,这个FrameBuffer就会被放到Cache中,来给其他的需要的地方进行使用。因此作者给GPUImageFrameBuffer引入了引用计数的概念。

    引用计数的概念其实和OC自带的MRC有点类似,每当一个地方需要使用这个FrameBuffer的时候,手动调用lock方法,使引用计数+1;当渲染完毕或者这个FrameBuffer使用完毕的时候,手动调用unlock方法,使引用计数-1;当引用计数为0的时候,FrameBuffer会被归还到Cache中。

    调用增加FrameBuffer引用计数方法的地方:

    1. 每次从Cache中获取到一个FrameBuffer的时候,都会调用一次lock方法,因为既然获取了FrameBuffer就是需要使用它进行渲染的时候,因此这个是最合适的调用时机;
    2. 将一个FrameBuffer作为Output传给下一个Input的时候,会调用setInputFrameBuffer:atIndex:方法。因为这个FrameBuffer会被传递给下一个input进行使用,因此我们需要手动的将这个FrameBuffer的引用计数+1;
    3. 如果需要将一个Filter的输出进行截图的话(usingNextFrameForImageCapture == YES),也需要手动调用lock方法。因为默认情况下,当下一个input渲染完成之后,就会释放这个FrameBuffer。如果你需要对当前的Filter的输出进行截图的话,则需要保留住这个FrameBuffer。

    调用减少FrameBuffer引用计数方法的地方:

    1. 在renderToTextureWithVertices:textureCoordinates:渲染完成之后,需要将从上一个Output中传过来的所有InputFrameBuffer都unlock掉;
    2. 在informTargetsAboutNewFrameAtTime:通知下一个input之后,需要将当前的这个Output中的outputFrameBuffer给unlock掉;

    不需要引用计数的情况:

    在有些地方我们是不需要使用引用计数的,比如GPUImagePicture。因为生成了Picture之后,它只会有一个outputFrameBuffer。而且这个frameBuffer只有在GPUImagePicture初始化的时候生成。因此这个FrameBuffer不能被释放,否则以后它的target就不能使用了。因此GPUImagePicture初始化的时候调用了disableReferenceCounting方法。只有当这个GPUImagePicture在dealloc的时候才能被释放。

  • 相关阅读:
    打造基于CentOS7的xfce最简工作环境
    Linux下C程序的编辑,编译和运行以及调试
    修正 XE6 TListView 上方 SearchBok 右边的清除钮显示
    TabControl 显示彩色的图示 (XE6 Firemonkey)
    TSwitch 中文简繁显示支持(XE6 Android)
    改变 TMemo 的背景颜色 (Firemonkey)
    修正 XE5 Android 键盘三个问题
    Delphi 收藏
    展示 Popup 的使用方法
    ListView 下拉更新 (支持 Android)
  • 原文地址:https://www.cnblogs.com/tmacforever/p/9116753.html
Copyright © 2011-2022 走看看