forked from BradLarson/GPUImage
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGPUImageBuffer.m
176 lines (138 loc) · 5.08 KB
/
GPUImageBuffer.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#import "GPUImageBuffer.h"
@interface GPUImageBuffer()
//Texture management
- (GLuint)generateTexture;
- (void)removeTexture:(GLuint)textureToRemove;
@end
@implementation GPUImageBuffer
@synthesize bufferSize = _bufferSize;
#pragma mark -
#pragma mark Initialization and teardown
- (id)init;
{
if (!(self = [self initWithFragmentShaderFromString:kGPUImagePassthroughFragmentShaderString]))
{
return nil;
}
bufferedTextures = [[NSMutableArray alloc] init];
[self initializeOutputTextureIfNeeded];
[bufferedTextures addObject:[NSNumber numberWithInt:outputTexture]];
_bufferSize = 1;
return self;
}
- (void)dealloc
{
for (NSNumber *currentTextureName in bufferedTextures)
{
[self removeTexture:[currentTextureName intValue]];
}
}
#pragma mark -
#pragma mark GPUImageInput
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
{
outputTextureRetainCount = [targets count];
static const GLfloat imageVertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
[self notifyTargetsAboutNewOutputTexture];
// Let the downstream video elements see the previous frame from the buffer before rendering a new one into place
[self informTargetsAboutNewFrameAtTime:frameTime];
// Move the last frame to the back of the buffer, if needed
if (_bufferSize > 1)
{
NSNumber *lastTextureName = [bufferedTextures objectAtIndex:0];
[bufferedTextures removeObjectAtIndex:0];
[bufferedTextures addObject:lastTextureName];
}
else
{
// Make sure the previous rendering has finished before enqueuing the current frame when simply delaying by one frame
glFinish();
}
// Render the new frame to the back of the buffer
[self renderToTextureWithVertices:imageVertices textureCoordinates:[[self class] textureCoordinatesForRotation:inputRotation] sourceTexture:filterSourceTexture];
}
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates sourceTexture:(GLuint)sourceTexture;
{
if (self.preventRendering)
{
return;
}
[GPUImageOpenGLESContext setActiveShaderProgram:filterProgram];
[self setFilterFBO];
glBindTexture(GL_TEXTURE_2D, [[bufferedTextures lastObject] intValue]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, [[bufferedTextures lastObject] intValue], 0);
glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, sourceTexture);
glUniform1i(filterInputTextureUniform, 2);
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
- (void)prepareForImageCapture;
{
// Disable this for now, until I figure out how to integrate the texture caches with a buffer like this
}
#pragma mark -
#pragma mark Managing targets
- (GLuint)textureForOutput;
{
return [[bufferedTextures objectAtIndex:0] intValue];
}
#pragma mark -
#pragma mark Texture management
- (GLuint)generateTexture;
{
GLuint newTextureName = 0;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &newTextureName);
glBindTexture(GL_TEXTURE_2D, newTextureName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// This is necessary for non-power-of-two textures
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
CGSize currentFBOSize = [self sizeOfFBO];
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)currentFBOSize.width, (int)currentFBOSize.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
return newTextureName;
}
- (void)removeTexture:(GLuint)textureToRemove;
{
glDeleteTextures(1, &textureToRemove);
}
#pragma mark -
#pragma mark Accessors
- (void)setBufferSize:(NSUInteger)newValue;
{
if ( (newValue == _bufferSize) || (newValue < 1) )
{
return;
}
if (newValue > _bufferSize)
{
NSUInteger texturesToAdd = newValue - _bufferSize;
for (NSUInteger currentTextureIndex = 0; currentTextureIndex < texturesToAdd; currentTextureIndex++)
{
[bufferedTextures addObject:[NSNumber numberWithInt:[self generateTexture]]];
}
}
else
{
NSUInteger texturesToRemove = _bufferSize - newValue;
for (NSUInteger currentTextureIndex = 0; currentTextureIndex < texturesToRemove; currentTextureIndex++)
{
NSNumber *lastTextureName = [bufferedTextures lastObject];
[bufferedTextures removeObjectAtIndex:([bufferedTextures count] - 1)];
[self removeTexture:[lastTextureName intValue]];
}
}
_bufferSize = newValue;
}
@end