前言
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);
项目地址
可以参考项目中
里面对正常的使用Texture id和使用IOS系统基于CVOpenGLESTextureCacheRef进行统一的接口封装