GPUImageFramebufferCache.m 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #import "GPUImageFramebufferCache.h"
  2. #import "GPUImageContext.h"
  3. #import "GPUImageOutput.h"
  4. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  5. #import <UIKit/UIKit.h>
  6. #else
  7. #endif
  8. @interface GPUImageFramebufferCache()
  9. {
  10. // NSCache *framebufferCache;
  11. NSMutableDictionary *framebufferCache;
  12. NSMutableDictionary *framebufferTypeCounts;
  13. NSMutableArray *activeImageCaptureList; // Where framebuffers that may be lost by a filter, but which are still needed for a UIImage, etc., are stored
  14. id memoryWarningObserver;
  15. dispatch_queue_t framebufferCacheQueue;
  16. }
  17. - (NSString *)hashForSize:(CGSize)size textureOptions:(GPUTextureOptions)textureOptions onlyTexture:(BOOL)onlyTexture;
  18. @end
  19. @implementation GPUImageFramebufferCache
  20. #pragma mark -
  21. #pragma mark Initialization and teardown
  22. - (id)init;
  23. {
  24. if (!(self = [super init]))
  25. {
  26. return nil;
  27. }
  28. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  29. memoryWarningObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
  30. [self purgeAllUnassignedFramebuffers];
  31. }];
  32. #else
  33. #endif
  34. // framebufferCache = [[NSCache alloc] init];
  35. framebufferCache = [[NSMutableDictionary alloc] init];
  36. framebufferTypeCounts = [[NSMutableDictionary alloc] init];
  37. activeImageCaptureList = [[NSMutableArray alloc] init];
  38. framebufferCacheQueue = dispatch_queue_create("com.sunsetlakesoftware.GPUImage.framebufferCacheQueue", NULL);
  39. return self;
  40. }
  41. #pragma mark -
  42. #pragma mark Framebuffer management
  43. - (NSString *)hashForSize:(CGSize)size textureOptions:(GPUTextureOptions)textureOptions onlyTexture:(BOOL)onlyTexture;
  44. {
  45. if (onlyTexture)
  46. {
  47. return [NSString stringWithFormat:@"%.1fx%.1f-%d:%d:%d:%d:%d:%d:%d-NOFB", size.width, size.height, textureOptions.minFilter, textureOptions.magFilter, textureOptions.wrapS, textureOptions.wrapT, textureOptions.internalFormat, textureOptions.format, textureOptions.type];
  48. }
  49. else
  50. {
  51. return [NSString stringWithFormat:@"%.1fx%.1f-%d:%d:%d:%d:%d:%d:%d", size.width, size.height, textureOptions.minFilter, textureOptions.magFilter, textureOptions.wrapS, textureOptions.wrapT, textureOptions.internalFormat, textureOptions.format, textureOptions.type];
  52. }
  53. }
  54. - (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)textureOptions onlyTexture:(BOOL)onlyTexture;
  55. {
  56. __block GPUImageFramebuffer *framebufferFromCache = nil;
  57. // dispatch_sync(framebufferCacheQueue, ^{
  58. runSynchronouslyOnVideoProcessingQueue(^{
  59. NSString *lookupHash = [self hashForSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];
  60. NSNumber *numberOfMatchingTexturesInCache = [framebufferTypeCounts objectForKey:lookupHash];
  61. NSInteger numberOfMatchingTextures = [numberOfMatchingTexturesInCache integerValue];
  62. if ([numberOfMatchingTexturesInCache integerValue] < 1)
  63. {
  64. // Nothing in the cache, create a new framebuffer to use
  65. framebufferFromCache = [[GPUImageFramebuffer alloc] initWithSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];
  66. }
  67. else
  68. {
  69. // Something found, pull the old framebuffer and decrement the count
  70. NSInteger currentTextureID = (numberOfMatchingTextures - 1);
  71. while ((framebufferFromCache == nil) && (currentTextureID >= 0))
  72. {
  73. NSString *textureHash = [NSString stringWithFormat:@"%@-%ld", lookupHash, (long)currentTextureID];
  74. framebufferFromCache = [framebufferCache objectForKey:textureHash];
  75. // Test the values in the cache first, to see if they got invalidated behind our back
  76. if (framebufferFromCache != nil)
  77. {
  78. // Withdraw this from the cache while it's in use
  79. [framebufferCache removeObjectForKey:textureHash];
  80. }
  81. currentTextureID--;
  82. }
  83. currentTextureID++;
  84. [framebufferTypeCounts setObject:[NSNumber numberWithInteger:currentTextureID] forKey:lookupHash];
  85. if (framebufferFromCache == nil)
  86. {
  87. framebufferFromCache = [[GPUImageFramebuffer alloc] initWithSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];
  88. }
  89. }
  90. });
  91. [framebufferFromCache lock];
  92. return framebufferFromCache;
  93. }
  94. - (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize onlyTexture:(BOOL)onlyTexture;
  95. {
  96. GPUTextureOptions defaultTextureOptions;
  97. defaultTextureOptions.minFilter = GL_LINEAR;
  98. defaultTextureOptions.magFilter = GL_LINEAR;
  99. defaultTextureOptions.wrapS = GL_CLAMP_TO_EDGE;
  100. defaultTextureOptions.wrapT = GL_CLAMP_TO_EDGE;
  101. defaultTextureOptions.internalFormat = GL_RGBA;
  102. defaultTextureOptions.format = GL_BGRA;
  103. defaultTextureOptions.type = GL_UNSIGNED_BYTE;
  104. return [self fetchFramebufferForSize:framebufferSize textureOptions:defaultTextureOptions onlyTexture:onlyTexture];
  105. }
  106. - (void)returnFramebufferToCache:(GPUImageFramebuffer *)framebuffer;
  107. {
  108. [framebuffer clearAllLocks];
  109. // dispatch_async(framebufferCacheQueue, ^{
  110. runAsynchronouslyOnVideoProcessingQueue(^{
  111. CGSize framebufferSize = framebuffer.size;
  112. GPUTextureOptions framebufferTextureOptions = framebuffer.textureOptions;
  113. NSString *lookupHash = [self hashForSize:framebufferSize textureOptions:framebufferTextureOptions onlyTexture:framebuffer.missingFramebuffer];
  114. NSNumber *numberOfMatchingTexturesInCache = [framebufferTypeCounts objectForKey:lookupHash];
  115. NSInteger numberOfMatchingTextures = [numberOfMatchingTexturesInCache integerValue];
  116. NSString *textureHash = [NSString stringWithFormat:@"%@-%ld", lookupHash, (long)numberOfMatchingTextures];
  117. // [framebufferCache setObject:framebuffer forKey:textureHash cost:round(framebufferSize.width * framebufferSize.height * 4.0)];
  118. [framebufferCache setObject:framebuffer forKey:textureHash];
  119. [framebufferTypeCounts setObject:[NSNumber numberWithInteger:(numberOfMatchingTextures + 1)] forKey:lookupHash];
  120. });
  121. }
  122. - (void)purgeAllUnassignedFramebuffers;
  123. {
  124. runAsynchronouslyOnVideoProcessingQueue(^{
  125. // dispatch_async(framebufferCacheQueue, ^{
  126. [framebufferCache removeAllObjects];
  127. [framebufferTypeCounts removeAllObjects];
  128. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  129. CVOpenGLESTextureCacheFlush([[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], 0);
  130. #else
  131. #endif
  132. });
  133. }
  134. - (void)addFramebufferToActiveImageCaptureList:(GPUImageFramebuffer *)framebuffer;
  135. {
  136. runAsynchronouslyOnVideoProcessingQueue(^{
  137. // dispatch_async(framebufferCacheQueue, ^{
  138. [activeImageCaptureList addObject:framebuffer];
  139. });
  140. }
  141. - (void)removeFramebufferFromActiveImageCaptureList:(GPUImageFramebuffer *)framebuffer;
  142. {
  143. runAsynchronouslyOnVideoProcessingQueue(^{
  144. // dispatch_async(framebufferCacheQueue, ^{
  145. [activeImageCaptureList removeObject:framebuffer];
  146. });
  147. }
  148. @end