# GPUImage源码解读(三)

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

[源码GPUImageContext](https://github.com/BradLarson/GPUImage/blob/master/framework/Source/iOS/GPUImageContext.h)

* 属性列表

```
// 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", NULL);

#if (!defined(__IPHONE_6_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0))
#else
    //设置队列标识 防止死锁 @see http://www.jianshu.com/p/a9066dde1f2b
    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相关特性的支持情况 获取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;
```

* 调整纹理大小，保证纹理不超过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];
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://philm.gitbook.io/philm-ios-wiki/mei-zhou-yue-du/gpuimage-yuan-ma-jie-du-san.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
