diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filter/MultiFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filter/MultiFilter.java index 1285a216..e660e55f 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filter/MultiFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filter/MultiFilter.java @@ -10,6 +10,8 @@ import com.otaliastudios.cameraview.size.Size; import com.otaliastudios.opengl.core.Egloo; import com.otaliastudios.opengl.program.GlProgram; import com.otaliastudios.opengl.program.GlTextureProgram; +import com.otaliastudios.opengl.texture.GlFramebuffer; +import com.otaliastudios.opengl.texture.GlTexture; import java.util.ArrayList; import java.util.Arrays; @@ -48,8 +50,8 @@ public class MultiFilter implements Filter, OneParameterFilter, TwoParameterFilt @VisibleForTesting boolean isFramebufferCreated = false; @VisibleForTesting Size size = null; private int programHandle = -1; - private int outputFramebufferId = -1; - private int outputTextureId = -1; + private GlFramebuffer outputFramebuffer = null; + private GlTexture outputTexture = null; } @VisibleForTesting final List filters = new ArrayList<>(); @@ -136,40 +138,12 @@ public class MultiFilter implements Filter, OneParameterFilter, TwoParameterFilt //noinspection ConstantConditions if (state.isFramebufferCreated || isLast) return; state.isFramebufferCreated = true; - - int[] framebufferArray = new int[1]; - int[] textureArray = new int[1]; - GLES20.glGenFramebuffers(1, framebufferArray, 0); - GLES20.glGenTextures(1, textureArray, 0); - state.outputFramebufferId = framebufferArray[0]; - state.outputTextureId = textureArray[0]; - - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, state.outputTextureId); - GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, - state.size.getWidth(), state.size.getHeight(), 0, GLES20.GL_RGBA, - GLES20.GL_UNSIGNED_BYTE, null); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, - GLES20.GL_LINEAR); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, - GLES20.GL_LINEAR); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, - GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, - GLES20.GL_CLAMP_TO_EDGE); - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, state.outputFramebufferId); - GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, - GLES20.GL_COLOR_ATTACHMENT0, + state.outputTexture = new GlTexture(GLES20.GL_TEXTURE0, GLES20.GL_TEXTURE_2D, - state.outputTextureId, - 0); - - int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER); - if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) { - throw new RuntimeException("Invalid framebuffer generation. Error:" + status); - } - - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); + state.size.getWidth(), + state.size.getHeight()); + state.outputFramebuffer = new GlFramebuffer(); + state.outputFramebuffer.attach(state.outputTexture); } private void maybeDestroyFramebuffer(@NonNull Filter filter) { @@ -177,10 +151,10 @@ public class MultiFilter implements Filter, OneParameterFilter, TwoParameterFilt //noinspection ConstantConditions if (!state.isFramebufferCreated) return; state.isFramebufferCreated = false; - GLES20.glDeleteFramebuffers(1, new int[]{state.outputFramebufferId}, 0); - state.outputFramebufferId = -1; - GLES20.glDeleteTextures(1, new int[]{state.outputTextureId}, 0); - state.outputTextureId = -1; + state.outputFramebuffer.release(); + state.outputFramebuffer = null; + state.outputTexture.release(); + state.outputTexture = null; } private void maybeSetSize(@NonNull Filter filter) { @@ -240,6 +214,7 @@ public class MultiFilter implements Filter, OneParameterFilter, TwoParameterFilt boolean isLast = i == filters.size() - 1; Filter filter = filters.get(i); State state = states.get(filter); + maybeSetSize(filter); maybeCreateProgram(filter, isFirst, isLast); maybeCreateFramebuffer(filter, isFirst, isLast); @@ -251,7 +226,7 @@ public class MultiFilter implements Filter, OneParameterFilter, TwoParameterFilt // Each filter outputs into its own framebuffer object, except the // last filter, which outputs into the default framebuffer. if (!isLast) { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, state.outputFramebufferId); + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, state.outputFramebuffer.getId()); GLES20.glClearColor(0, 0, 0, 0); } else { GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); @@ -270,7 +245,7 @@ public class MultiFilter implements Filter, OneParameterFilter, TwoParameterFilt // It is the framebuffer texture from this cycle. If this is the last // filter, reset this value just to cleanup. if (!isLast) { - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, state.outputTextureId); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, state.outputTexture.getId()); } else { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); } @@ -285,6 +260,9 @@ public class MultiFilter implements Filter, OneParameterFilter, TwoParameterFilt public Filter copy() { synchronized (lock) { MultiFilter copy = new MultiFilter(); + if (size != null) { + copy.setSize(size.getWidth(), size.getHeight()); + } for (Filter filter : filters) { copy.addFilter(filter.copy()); }