GPUImage源码解读(五)

  • GPUImageFramebufferCache

    GPUImageFramebufferCache类核心的职责是管理GPUImageFramebuffer对象。

  • 方法列表 主要涉及到在缓存中查找 GPUImageFramebuffer,将 GPUImageFramebuffer 加入缓存,清空缓存等相关方法。

/**
 从cache中获取一个GPUImageFramebuffer对象,如果获取失败,那么创建一个新的GPUImageFramebuffer对象。

 @param framebufferSize 对象的大小
 @param textureOptions 纹理的配置信息
 @param onlyTexture  指示是否只为纹理,是否包含framebuffer对象
 @return 返回framebuffer
 */
- (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)textureOptions onlyTexture:(BOOL)onlyTexture;
- (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize onlyTexture:(BOOL)onlyTexture;
  • 实现方法

- (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)textureOptions onlyTexture:(BOOL)onlyTexture;
{
    __block GPUImageFramebuffer *framebufferFromCache = nil;
//    dispatch_sync(framebufferCacheQueue, ^{
    runSynchronouslyOnVideoProcessingQueue(^{

        // 创建查找字符串
        NSString *lookupHash = [self hashForSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];

        // 获取GPUImageFramebuffer在缓存中的数量
        NSNumber *numberOfMatchingTexturesInCache = [framebufferTypeCounts objectForKey:lookupHash];
        NSInteger numberOfMatchingTextures = [numberOfMatchingTexturesInCache integerValue];
        // 缓存中如果没有,则创建framebufferFromCache
        if ([numberOfMatchingTexturesInCache integerValue] < 1)
        {
            // Nothing in the cache, create a new framebuffer to use
            framebufferFromCache = [[GPUImageFramebuffer alloc] initWithSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];
        }
        else
        {
            // Something found, pull the old framebuffer and decrement the count
            NSInteger currentTextureID = (numberOfMatchingTextures - 1);
            while ((framebufferFromCache == nil) && (currentTextureID >= 0))
            {
                // 根据数量构建带数量的textureHash字符串
                NSString *textureHash = [NSString stringWithFormat:@"%@-%ld", lookupHash, (long)currentTextureID];
                // 查找以textureHash为key的GPUImageFramebuffer是否存在
                framebufferFromCache = [framebufferCache objectForKey:textureHash];
                // Test the values in the cache first, to see if they got invalidated behind our back
                if (framebufferFromCache != nil)
                {
                    // Withdraw this from the cache while it's in use
                    [framebufferCache removeObjectForKey:textureHash];
                }
                currentTextureID--;
            }

            currentTextureID++;
            // 更新framebufferTypeCounts中相同类型(纹理属性GPUTextureOptions)GPUImageFramebuffer的数量
            [framebufferTypeCounts setObject:[NSNumber numberWithInteger:currentTextureID] forKey:lookupHash];
            // 还是没有则创建
            if (framebufferFromCache == nil)
            {
                framebufferFromCache = [[GPUImageFramebuffer alloc] initWithSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];
            }
        }
    });

     // 引用计数加1,返回
    [framebufferFromCache lock];
    return framebufferFromCache;
}

- (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize onlyTexture:(BOOL)onlyTexture;
{
    //默认的GPUTextureOptions查找
    GPUTextureOptions defaultTextureOptions;
    defaultTextureOptions.minFilter = GL_LINEAR;
    defaultTextureOptions.magFilter = GL_LINEAR;
    defaultTextureOptions.wrapS = GL_CLAMP_TO_EDGE;
    defaultTextureOptions.wrapT = GL_CLAMP_TO_EDGE;
    defaultTextureOptions.internalFormat = GL_RGBA;
    defaultTextureOptions.format = GL_BGRA;
    defaultTextureOptions.type = GL_UNSIGNED_BYTE;

    return [self fetchFramebufferForSize:framebufferSize textureOptions:defaultTextureOptions onlyTexture:onlyTexture];
}
  • 添加缓存

/**
 向GPUImageFramebuffer缓存加添加GPUImageFramebuffer对象

 @param framebuffer 需要添加的对象
 */
- (void)returnFramebufferToCache:(GPUImageFramebuffer *)framebuffer;
  • 实现方法

- (void)returnFramebufferToCache:(GPUImageFramebuffer *)framebuffer;
{
    // 清除引用计数
    [framebuffer clearAllLocks];

//    dispatch_async(framebufferCacheQueue, ^{
    runAsynchronouslyOnVideoProcessingQueue(^{
        CGSize framebufferSize = framebuffer.size;

        GPUTextureOptions framebufferTextureOptions = framebuffer.textureOptions;

        // 常见查找hash字符串
        NSString *lookupHash = [self hashForSize:framebufferSize textureOptions:framebufferTextureOptions onlyTexture:framebuffer.missingFramebuffer];
      // 获取当前同类型缓存的数量
        NSNumber *numberOfMatchingTexturesInCache = [framebufferTypeCounts objectForKey:lookupHash];
        NSInteger numberOfMatchingTextures = [numberOfMatchingTexturesInCache integerValue];

        // 对相同类型的GPUImageFramebuffer,存放在framebufferCache中时,key值由lookupHash加上数量避免覆盖相同的GPUImageFramebuffer。
        NSString *textureHash = [NSString stringWithFormat:@"%@-%ld", lookupHash, (long)numberOfMatchingTextures];

//        [framebufferCache setObject:framebuffer forKey:textureHash cost:round(framebufferSize.width * framebufferSize.height * 4.0)];
        [framebufferCache setObject:framebuffer forKey:textureHash];

        // framebufferTypeCounts中的key没有加数量
        [framebufferTypeCounts setObject:[NSNumber numberWithInteger:(numberOfMatchingTextures + 1)] forKey:lookupHash];
    });
}
  • 清空缓存, 内存警告的时候, 清理缓存中的纹理缓存,清理framebufferCache中的所有对象,在init中方法监听memoryWarningObserver

//收到 memory warning 时触发释放内存
- (void)purgeAllUnassignedFramebuffers;
{
    runAsynchronouslyOnVideoProcessingQueue(^{
//    dispatch_async(framebufferCacheQueue, ^{
        [framebufferCache removeAllObjects];
        [framebufferTypeCounts removeAllObjects];
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        CVOpenGLESTextureCacheFlush([[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], 0);
#else
#endif
    });
}
  • 帧缓存持有与释放。在读取帧缓存图像数据时,需要保持对 GPUImageFramebuffer 的引用。并且读取完数据后,需要对其进行释放。详细见 GPUImageFramebuffer 的 newCGImageFromFramebufferContents 方法。

- (void)addFramebufferToActiveImageCaptureList:(GPUImageFramebuffer *)framebuffer;
{
    runAsynchronouslyOnVideoProcessingQueue(^{
//    dispatch_async(framebufferCacheQueue, ^{
        [activeImageCaptureList addObject:framebuffer];
    });
}

- (void)removeFramebufferFromActiveImageCaptureList:(GPUImageFramebuffer *)framebuffer;
{
    runAsynchronouslyOnVideoProcessingQueue(^{
//  dispatch_async(framebufferCacheQueue, ^{
        [activeImageCaptureList removeObject:framebuffer];
    });
}

Last updated