GPUImage源码解读之GPUImageContext

GPUImageContext类,提供OpenGL ES基本上下文,GPUImage相关处理线程,GLProgram缓存、帧缓存。由于是上下文对象,因此该模块提供的更多是存取、设置相关的方法。

  • 属性列表
// GPUImage处理OpenGL绘制的相关队列,串行队列
@property(readonly, nonatomic) dispatch_queue_t contextQueue;
// 当前使用的着色器程序
@property(readwrite, retain, nonatomic) GLProgram *currentShaderProgram;
// OpenGLES上下文对象
@property(readonly, retain, nonatomic) EAGLContext *context;
// CoreVideo中的纹理缓存
@property(readonly) CVOpenGLESTextureCacheRef coreVideoTextureCache;
// 帧缓存
@property(readonly) GPUImageFramebufferCache *framebufferCache;
  • 初始化过程。在初始化的过程中通过dispatch_queue_set_specific设置队列标识
- (id)init;
{
    if (!(self = [super init]))
    {
        return nil;
    }
    
    // 创建OpenGL渲染队列
    openGLESContextQueueKey = &openGLESContextQueueKey;
    _contextQueue = dispatch_queue_create("com.sunsetlakesoftware.GPUImage.openGLESContextQueue", GPUImageDefaultQueueAttribute());
    
#if OS_OBJECT_USE_OBJC
    // 设置队列标识
    dispatch_queue_set_specific(_contextQueue, openGLESContextQueueKey, (__bridge void *)self, NULL);
#endif
    // 初始化着色器缓存相关数组
    shaderProgramCache = [[NSMutableDictionary alloc] init];
    shaderProgramUsageHistory = [[NSMutableArray alloc] init];
    
    return self;
}
  • 方法列表
// 获取队列标识
+ (void *)contextKey;
// 单例对象
+ (GPUImageContext *)sharedImageProcessingContext;
// 获取处理队列
+ (dispatch_queue_t)sharedContextQueue;
// 帧缓存
+ (GPUImageFramebufferCache *)sharedFramebufferCache;
// 设置当前上下文
+ (void)useImageProcessingContext;
- (void)useAsCurrentContext;
// 设置当前的GL程序
+ (void)setActiveShaderProgram:(GLProgram *)shaderProgram;
- (void)setContextShaderProgram:(GLProgram *)shaderProgram;
// 获取设备OpenGLES相关特性的支持情况
+ (GLint)maximumTextureSizeForThisDevice;
+ (GLint)maximumTextureUnitsForThisDevice;
+ (GLint)maximumVaryingVectorsForThisDevice;
+ (BOOL)deviceSupportsOpenGLESExtension:(NSString *)extension;
+ (BOOL)deviceSupportsRedTextures;
+ (BOOL)deviceSupportsFramebufferReads;
// 纹理大小调整,保证纹理不超过OpenGLES支持最大的尺寸
+ (CGSize)sizeThatFitsWithinATextureForSize:(CGSize)inputSize;
// 将渲染缓存呈现在设备上
- (void)presentBufferForDisplay;
// 创建GLProgram,首先在缓存中查找,如果没有则创建
- (GLProgram *)programForVertexShaderString:(NSString *)vertexShaderString fragmentShaderString:(NSString *)fragmentShaderString;
// 创建Sharegroup
- (void)useSharegroup:(EAGLSharegroup *)sharegroup;
// Manage fast texture upload
+ (BOOL)supportsFastTextureUpload;

由于GPUImageContext相当于一个上下文对象,主要是管理其它的对象,因此该类没有太多复杂的业务,这里主要看一下几个方法:

  • 调整纹理大小,保证纹理不超过OpenGLES支持最大的尺寸:
+ (CGSize)sizeThatFitsWithinATextureForSize:(CGSize)inputSize;
{
    GLint maxTextureSize = [self maximumTextureSizeForThisDevice]; 
    if ( (inputSize.width < maxTextureSize) && (inputSize.height < maxTextureSize) )
    {
        return inputSize;
    }
    
    CGSize adjustedSize;
    if (inputSize.width > inputSize.height)
    {
        adjustedSize.width = (CGFloat)maxTextureSize;
        adjustedSize.height = ((CGFloat)maxTextureSize / inputSize.width) * inputSize.height;
    }
    else
    {
        adjustedSize.height = (CGFloat)maxTextureSize;
        adjustedSize.width = ((CGFloat)maxTextureSize / inputSize.height) * inputSize.width;
    }

    return adjustedSize;
}
  • 获取OpenGLES支持的最大纹理尺寸
+ (GLint)maximumTextureSizeForThisDevice;
{
    static dispatch_once_t pred;
    static GLint maxTextureSize = 0;
    
    dispatch_once(&pred, ^{
        [self useImageProcessingContext];
        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
    });

    return maxTextureSize;
}

  • 创建GLProgram,首先在缓存中查找,如果没有则创建
- (GLProgram *)programForVertexShaderString:(NSString *)vertexShaderString fragmentShaderString:(NSString *)fragmentShaderString;
{
    NSString *lookupKeyForShaderProgram = [NSString stringWithFormat:@"V: %@ - F: %@", vertexShaderString, fragmentShaderString];
    GLProgram *programFromCache = [shaderProgramCache objectForKey:lookupKeyForShaderProgram];

    if (programFromCache == nil)
    {
        programFromCache = [[GLProgram alloc] initWithVertexShaderString:vertexShaderString fragmentShaderString:fragmentShaderString];
        [shaderProgramCache setObject:programFromCache forKey:lookupKeyForShaderProgram];
//        [shaderProgramUsageHistory addObject:lookupKeyForShaderProgram];
//        if ([shaderProgramUsageHistory count] >= MAXSHADERPROGRAMSALLOWEDINCACHE)
//        {
//            for (NSUInteger currentShaderProgramRemovedFromCache = 0; currentShaderProgramRemovedFromCache < 10; currentShaderProgramRemovedFromCache++)
//            {
//                NSString *shaderProgramToRemoveFromCache = [shaderProgramUsageHistory objectAtIndex:0];
//                [shaderProgramUsageHistory removeObjectAtIndex:0];
//                [shaderProgramCache removeObjectForKey:shaderProgramToRemoveFromCache];
//            }
//        }
    }
    
    return programFromCache;
}
  • 创建EAGLContext上下文对象,使用的是kEAGLRenderingAPIOpenGLES2的API也就是OpenGL ES 2.0
- (EAGLContext *)createContext;
{
    EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:_sharegroup];
    NSAssert(context != nil, @"Unable to create an OpenGL ES 2.0 context. The GPUImage framework requires OpenGL ES 2.0 support to work.");
    return context;
}

  • 设置当前的上下文对象,以及当前的着色器程序
- (void)setContextShaderProgram:(GLProgram *)shaderProgram;
{
    EAGLContext *imageProcessingContext = [self context];
    if ([EAGLContext currentContext] != imageProcessingContext)
    {
        [EAGLContext setCurrentContext:imageProcessingContext];
    }
    
    if (self.currentShaderProgram != shaderProgram)
    {
        self.currentShaderProgram = shaderProgram;
        [shaderProgram use];
    }
}

总结

GLProgram 与着色器程序创建息息相关,其中包括创建、编译、链接、使用等过程。
GPUImageContext 是GPUImage的上下文对象,管理着OpenGLES上下文对象,管理着GL程序,管理着帧缓存等GPUImage中的基本组件。

posted @ 2018-06-01 10:36  简丛  阅读(794)  评论(0编辑  收藏  举报