GPUImageContext.m 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #import "GPUImageContext.h"
  2. #import <AVFoundation/AVFoundation.h>
  3. @interface GPUImageContext()
  4. {
  5. NSMutableDictionary *shaderProgramCache;
  6. CGLShareGroupObj *_sharegroup;
  7. }
  8. @end
  9. @implementation GPUImageContext
  10. @synthesize context = _context;
  11. @synthesize currentShaderProgram = _currentShaderProgram;
  12. @synthesize contextQueue = _contextQueue;
  13. @synthesize framebufferCache = _framebufferCache;
  14. static void *openGLESContextQueueKey;
  15. - (id)init;
  16. {
  17. if (!(self = [super init]))
  18. {
  19. return nil;
  20. }
  21. openGLESContextQueueKey = &openGLESContextQueueKey;
  22. _contextQueue = dispatch_queue_create("com.sunsetlakesoftware.GPUImage.openGLESContextQueue", NULL);
  23. dispatch_queue_set_specific(_contextQueue, openGLESContextQueueKey, (__bridge void *)self, NULL);
  24. shaderProgramCache = [[NSMutableDictionary alloc] init];
  25. return self;
  26. }
  27. + (void *)contextKey {
  28. return openGLESContextQueueKey;
  29. }
  30. // Based on Colin Wheeler's example here: http://cocoasamurai.blogspot.com/2011/04/singletons-your-doing-them-wrong.html
  31. + (GPUImageContext *)sharedImageProcessingContext;
  32. {
  33. static dispatch_once_t pred;
  34. static GPUImageContext *sharedImageProcessingContext = nil;
  35. dispatch_once(&pred, ^{
  36. sharedImageProcessingContext = [[[self class] alloc] init];
  37. });
  38. return sharedImageProcessingContext;
  39. }
  40. + (dispatch_queue_t)sharedContextQueue;
  41. {
  42. return [[self sharedImageProcessingContext] contextQueue];
  43. }
  44. + (GPUImageFramebufferCache *)sharedFramebufferCache;
  45. {
  46. return [[self sharedImageProcessingContext] framebufferCache];
  47. }
  48. + (void)useImageProcessingContext;
  49. {
  50. NSOpenGLContext *imageProcessingContext = [[GPUImageContext sharedImageProcessingContext] context];
  51. if ([NSOpenGLContext currentContext] != imageProcessingContext)
  52. {
  53. [imageProcessingContext makeCurrentContext];
  54. }
  55. }
  56. + (void)setActiveShaderProgram:(GLProgram *)shaderProgram;
  57. {
  58. GPUImageContext *sharedContext = [GPUImageContext sharedImageProcessingContext];
  59. NSOpenGLContext *imageProcessingContext = [sharedContext context];
  60. if ([NSOpenGLContext currentContext] != imageProcessingContext)
  61. {
  62. [imageProcessingContext makeCurrentContext];
  63. }
  64. if (sharedContext.currentShaderProgram != shaderProgram)
  65. {
  66. sharedContext.currentShaderProgram = shaderProgram;
  67. [shaderProgram use];
  68. }
  69. }
  70. + (GLint)maximumTextureSizeForThisDevice;
  71. {
  72. static dispatch_once_t pred;
  73. static GLint maxTextureSize = 0;
  74. dispatch_once(&pred, ^{
  75. [self useImageProcessingContext];
  76. glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
  77. });
  78. return maxTextureSize;
  79. }
  80. + (GLint)maximumTextureUnitsForThisDevice;
  81. {
  82. GLint maxTextureUnits;
  83. glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
  84. return maxTextureUnits;
  85. }
  86. + (BOOL)deviceSupportsOpenGLESExtension:(NSString *)extension;
  87. {
  88. static dispatch_once_t pred;
  89. static NSArray *extensionNames = nil;
  90. // Cache extensions for later quick reference, since this won't change for a given device
  91. dispatch_once(&pred, ^{
  92. [GPUImageContext useImageProcessingContext];
  93. NSString *extensionsString = [NSString stringWithCString:(const char *)glGetString(GL_EXTENSIONS) encoding:NSASCIIStringEncoding];
  94. extensionNames = [extensionsString componentsSeparatedByString:@" "];
  95. });
  96. return [extensionNames containsObject:extension];
  97. }
  98. + (BOOL)deviceSupportsFramebufferReads;
  99. {
  100. return NO;
  101. }
  102. // http://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_rg.txt
  103. + (BOOL)deviceSupportsRedTextures;
  104. {
  105. static dispatch_once_t pred;
  106. static BOOL supportsRedTextures = NO;
  107. dispatch_once(&pred, ^{
  108. supportsRedTextures = [GPUImageContext deviceSupportsOpenGLESExtension:@"GL_EXT_texture_rg"];
  109. });
  110. return supportsRedTextures;
  111. }
  112. + (CGSize)sizeThatFitsWithinATextureForSize:(CGSize)inputSize;
  113. {
  114. GLint maxTextureSize = [self maximumTextureSizeForThisDevice];
  115. if ( (inputSize.width < maxTextureSize) && (inputSize.height < maxTextureSize) )
  116. {
  117. return inputSize;
  118. }
  119. CGSize adjustedSize;
  120. if (inputSize.width > inputSize.height)
  121. {
  122. adjustedSize.width = (CGFloat)maxTextureSize;
  123. adjustedSize.height = ((CGFloat)maxTextureSize / inputSize.width) * inputSize.height;
  124. }
  125. else
  126. {
  127. adjustedSize.height = (CGFloat)maxTextureSize;
  128. adjustedSize.width = ((CGFloat)maxTextureSize / inputSize.height) * inputSize.width;
  129. }
  130. return adjustedSize;
  131. }
  132. - (void)presentBufferForDisplay;
  133. {
  134. [self.context flushBuffer];
  135. }
  136. - (GLProgram *)programForVertexShaderString:(NSString *)vertexShaderString fragmentShaderString:(NSString *)fragmentShaderString;
  137. {
  138. NSString *lookupKeyForShaderProgram = [NSString stringWithFormat:@"V: %@ - F: %@", vertexShaderString, fragmentShaderString];
  139. GLProgram *programFromCache = [shaderProgramCache objectForKey:lookupKeyForShaderProgram];
  140. if (programFromCache == nil)
  141. {
  142. programFromCache = [[GLProgram alloc] initWithVertexShaderString:vertexShaderString fragmentShaderString:fragmentShaderString];
  143. [shaderProgramCache setObject:programFromCache forKey:lookupKeyForShaderProgram];
  144. }
  145. return programFromCache;
  146. }
  147. - (void)useSharegroup:(CGLShareGroupObj *)sharegroup;
  148. {
  149. NSAssert(_context == nil, @"Unable to use a share group when the context has already been created. Call this method before you use the context for the first time.");
  150. _sharegroup = sharegroup;
  151. }
  152. - (NSOpenGLContext *)createContext;
  153. {
  154. NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = {
  155. NSOpenGLPFADoubleBuffer,
  156. NSOpenGLPFAAccelerated, 0,
  157. 0
  158. };
  159. NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes];
  160. if (pixelFormat == nil)
  161. {
  162. NSLog(@"Error: No appropriate pixel format found");
  163. }
  164. // TODO: Take into account the sharegroup
  165. NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
  166. NSAssert(context != nil, @"Unable to create an OpenGL context. The GPUImage framework requires OpenGL support to work.");
  167. return context;
  168. }
  169. #pragma mark -
  170. #pragma mark Manage fast texture upload
  171. + (BOOL)supportsFastTextureUpload;
  172. {
  173. // This may need to be redone to account for the Mac's accelerated data transfer methods
  174. return NO;
  175. }
  176. #pragma mark -
  177. #pragma mark Accessors
  178. - (NSOpenGLContext *)context;
  179. {
  180. if (_context == nil)
  181. {
  182. _context = [self createContext];
  183. [_context makeCurrentContext];
  184. // Set up a few global settings for the image processing pipeline
  185. glDisable(GL_DEPTH_TEST);
  186. glEnable(GL_TEXTURE_2D);
  187. }
  188. return _context;
  189. }
  190. - (GPUImageFramebufferCache *)framebufferCache;
  191. {
  192. if (_framebufferCache == nil)
  193. {
  194. _framebufferCache = [[GPUImageFramebufferCache alloc] init];
  195. }
  196. return _framebufferCache;
  197. }
  198. @end