I use GPUImageFilterGroup to apply some filters to a image. All filters stable (all parameters is constant), but last filter is variable (some parameter is changed).
I need redraw image after last filter was changed.
Now I call processImage on source GPUImagePicture, but this invocation redraw all filters and speed is too slow.
How can I redraw only last filter in the group?
I think, I should save copy of a frame buffer before last filter will draw, and when I've change some parameter in the last filter, I should use saved frame buffer to redraw last filter. But I can't find how I can save copy of the frame buffer.
I've solved this, by subclassing GPUImageFilter and GPUImageFilterGroup. In GPUImageFilter I've overloaded method
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex
<...>
[self renderToTextureWithVertices:imageVertices textureCoordinates:[[self class] textureCoordinatesForRotation:inputRotation]];
_bufferCallback(self);
[self informTargetsAboutNewFrameAtTime:frameTime];
<...>
In GPUImageFilterGroup I've overloaded methods:
- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter
{
NSParameterAssert([newFilter isKindOfClass: [FAEShiftFilterWithBackOutputBuffer class]]);
if ([newFilter isKindOfClass:[FAEShiftFilterWithBackOutputBuffer class]])
{
__weak typeof(self) selfWeak = self;
[(FAEShiftFilterWithBackOutputBuffer*)newFilter setOutputBufferCallback:^(FAEShiftFilterWithBackOutputBuffer *sender) {
__strong typeof(selfWeak) selfStrong = selfWeak;
if (selfStrong)
{
if (!selfStrong.lastFramebuffer)
{
if ([selfStrong isPreLastFilter:sender])
{
selfStrong.lastFramebuffer = [sender framebufferForOutput];
[selfStrong.lastFramebuffer lock];
}
}
}
}];
}
[super addFilter:newFilter];
}
This method stores outputFrameBuffer from preLast filter. And method:
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex
{
if (self.filterCount > 1)
{
if (self.lastFramebuffer)
{
GPUImageFilter* lastFilter = (GPUImageFilter*)self.terminalFilter;
[lastFilter setInputFramebuffer:self.lastFramebuffer atIndex:0];
[lastFilter newFrameReadyAtTime:frameTime atIndex:textureIndex];
}
else
{
[super newFrameReadyAtTime:frameTime atIndex:textureIndex];
}
}
else
{
[super newFrameReadyAtTime:frameTime atIndex:textureIndex];
}
}
Also I reset saved framebuffer in dealloc and forceProcessingAtSize and forceProcessingAtSizeRespectingAspectRatio methods.
- (void)_clearLastFrameBuffer
{
if (_lastFramebuffer)
{
[_lastFramebuffer unlock];
_lastFramebuffer = nil;
}
}