OpenGLES之CVOpenGLESTextureCache介绍(八)

前言

ios系统的CVOpenGLESTextureCacheRef 位于<CoreVideo/CoreVideo.h>中,专门用来处于视频纹理渲染的高效纹理缓冲区,
它配合CMMemoryPoolRef使用,将创建一个纹理缓冲区。
工作原理就是创建一块专门用于存放纹理的缓冲区(由CMMemoryPoolRef负责管理),这样每次应用端传递纹理像素数据给GPU时,直接使用这个缓冲区中的内存,而不用重新创建。避免了重复创建,提高了效率。
本文将介绍如何使用基于CVOpenGLESTextureCacheRef和CMMemoryPoolRef的纹理缓冲区系统

opengl es系列文章

opengl es之-基础概念(一)
opengl es之-GLSL语言(二)
opengl es之-GLSL语言(三)
opengl es之-常用函数介绍(四)
opengl es之-渲染两张图片(五)
opengl es之-在图片上添加对角线(六)
opengl es之-离屏渲染简介(七)
opengl es之-CVOpenGLESTextureCache介绍(八)
opengl es之-播放YUV文件(九)

需求

从该缓冲区系统的创建,FBO帧缓冲区的纹理句柄的生成,及纹理的上传三个方面熟悉CVOpenGLESTextureCacheRef的使用

创建CVOpenGLESTextureCacheRef对象

- (CVOpenGLESTextureCacheRef)coreVideoTextureCache
{
    if (_coreVideoTextureCache == NULL) {
        CVReturn result = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, _context, NULL, &_coreVideoTextureCache);
        if (result != kCVReturnSuccess) {
            NSLog(@"CVOpenGLESTextureCacheCreate fail %d",result);
        }
    }
    
    return _coreVideoTextureCache;
}

将分配一个CVOpenGLESTextureCacheRef对象
这套缓存区管理系统再收到内存不够的警告时还需要有一定的自动清理机制,通过调用
CVOpenGLESTextureCacheFlush()函数实现,该函数将自动减少缓冲区中的内存,使用方式如下:

// 收到内存不足警告后,需要清除部分内存
__unsafe_unretained __typeof__ (self) weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification
                                                          object:nil
                                                           queue:nil
                                                      usingBlock:^(NSNotification *notification) {
                                                          __typeof__ (self) strongSelf = weakSelf;
                                                          if (strongSelf) {
                                                              CVOpenGLESTextureCacheFlush([strongSelf coreVideoTextureCache], 0);
                                                          }
                                                      }];

模拟器是不支持该系统的

#pragma mark -
#pragma mark Manage fast texture upload
+ (BOOL)supportsFastTextureUpload;
{
#if TARGET_IPHONE_SIMULATOR
    return NO;
#else
    
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
    return (CVOpenGLESTextureCacheCreate != NULL);
#pragma clang diagnostic pop
    
#endif
}

FBO帧缓冲区的纹理句柄的生成,及纹理的上传

准备工作

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

纹理句柄及存放纹理的像素缓冲区的生成

CVOpenGLESTextureCacheRef textureCache = [_context coreVideoTextureCache];
        // Code originally sourced from http://allmybrain.com/2011/12/08/rendering-to-a-texture-with-ios-5-texture-cache-api/
CFDictionaryRef empty;
CFMutableDictionaryRef attrs;
empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
 /** CVPixelBufferCreate()两个函数作用相当于
  *  kCVPixelFormatType_32BGRA:相当于glTexImage2D()倒数第三个参数,定义像素数据的格式
  *  attrs:定义纹理的其它属性
  *  renderTarget:最终将生成一个CVPixelBufferRef类型的像素块,默认值为0,相当于void *pixbuffer = (void*)malloc(size);
  *  最终将根据传入参数,宽、高,像素格式,和属性生成一个用于存储像素的内存块
  */
CVReturn err = CVPixelBufferCreate(kCFAllocatorDefault, (size_t)_size.width, (size_t)_size.height, kCVPixelFormatType_32BGRA, attrs, &renderTarget);
if (err) {
    NSLog(@"FBO size: %f, %f", _size.width, _size.height);
    NSAssert(NO, @"Error at CVPixelBufferCreate %d", err);
}
        
/** 该函数有两个作用:
 *  1、renderTarget像素数据传给opengl es,类似于相当于glTexImage2D(),当然renderTarget中数据可以是由CVPixelBufferCreate()创建的默认值都是
 *  0的像素数据,也可以是具体的像素数据
 *  2、生成对应格式的CVOpenGLESTextureRef对象(相当于glGenTextures()生成的texture id)
 *  CVOpenGLESTextureRef对象(它是对Opengl es中由glGenTextures()生成的texture id的封装)
 */
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                            textureCache,
                            renderTarget,
                            NULL, // texture attributes
                            GL_TEXTURE_2D,
                            _textureOptions.internalFormat, // opengl format,相当于glTexImage2D()函数第三个参数
                            (int)_size.width,(int)_size.height,
                            _textureOptions.format, // native iOS format,相当于glTexImage2D()函数倒数第三个参数,这里即renderTarget的像素格式,这里是IOS系统默认的BGRA数据格式
                            _textureOptions.type,// 相当于glTexImage2D()函数第二个参数
                            0,// 对于planner存储方式的像素数据,这里填写对应的索引。非planner格式写0即可
                            &renderTexture);// 生成texture id
if (err){
            NSAssert(NO, @"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
}
        
CFRelease(attrs);
CFRelease(empty);

上面的代码首先由CVPixelBufferCreate()函数生成了一个CVPixelBufferRef对象,该对象作为像素数据的载体,最终由CVOpenGLESTextureCacheCreateTextureFromImage()函数传递给opengl es

纹理对象CVOpenGLESTextureRef是由CVOpenGLESTextureCacheCreateTextureFromImage()函数创建,可以把它看做是对opengl es中由glGenTextures()函数创建的texture id的封装
这里对这个函数说明一下:

1、renderTarget像素数据传给opengl es,类似于相当于glTexImage2D(),当然renderTarget中数据可以是由CVPixelBufferCreate()创建的默认值都是
2、生成对应格式的CVOpenGLESTextureRef对象(相当于glGenTextures()生成的texture id)
* CVOpenGLESTextureRef对象(它是对Opengl es中由glGenTextures()生成的texture id的封装)

CVOpenGLESTextureGetTarget(renderTexture)函数可以获取到Texture id
那么接下来的使用就和普通的opengl es流程一样了;比如需要绑定Texture,设置Texture类型的参数等等

// 那么接下来的使用就和普通的opengl es流程一样了;
glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture));
// 由CVOpenGLESTextureCacheRef方式来管理纹理,则通过此方法来获取texture id;
_texture = CVOpenGLESTextureGetName(renderTexture);  
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _textureOptions.minFilter);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _textureOptions.magFilter);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureOptions.wrapS);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _textureOptions.wrapT);

项目地址

可以参考项目中


1559981671184.jpg

里面对正常的使用Texture id和使用IOS系统基于CVOpenGLESTextureCacheRef进行统一的接口封装

Demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容