diff --git a/talk/app/webrtc/java/android/org/webrtc/GlTextureFrameBuffer.java b/talk/app/webrtc/java/android/org/webrtc/GlTextureFrameBuffer.java new file mode 100644 index 0000000000..fd52c37eb4 --- /dev/null +++ b/talk/app/webrtc/java/android/org/webrtc/GlTextureFrameBuffer.java @@ -0,0 +1,142 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.webrtc; + +import android.opengl.GLES20; + +/** + * Helper class for handling OpenGL framebuffer with only color attachment and no depth or stencil + * buffer. Intended for simple tasks such as texture copy, texture downscaling, and texture color + * conversion. + */ +// TODO(magjed): Add unittests for this class. +public class GlTextureFrameBuffer { + private final int frameBufferId; + private final int textureId; + private final int pixelFormat; + private int width; + private int height; + + /** + * Generate texture and framebuffer resources. An EGLContext must be bound on the current thread + * when calling this function. The framebuffer is not complete until setSize() is called. + */ + public GlTextureFrameBuffer(int pixelFormat) { + switch (pixelFormat) { + case GLES20.GL_LUMINANCE: + case GLES20.GL_RGB: + case GLES20.GL_RGBA: + this.pixelFormat = pixelFormat; + break; + default: + throw new IllegalArgumentException("Invalid pixel format: " + pixelFormat); + } + + textureId = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); + this.width = 0; + this.height = 0; + + // Create framebuffer object and bind it. + final int frameBuffers[] = new int[1]; + GLES20.glGenFramebuffers(1, frameBuffers, 0); + frameBufferId = frameBuffers[0]; + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId); + GlUtil.checkNoGLES2Error("Generate framebuffer"); + + // Attach the texture to the framebuffer as color attachment. + GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, + GLES20.GL_TEXTURE_2D, textureId, 0); + GlUtil.checkNoGLES2Error("Attach texture to framebuffer"); + + // Restore normal framebuffer. + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); + } + + /** + * (Re)allocate texture. Will do nothing if the requested size equals the current size. An + * EGLContext must be bound on the current thread when calling this function. Must be called at + * least once before using the framebuffer. May be called multiple times to change size. + */ + public void setSize(int width, int height) { + if (width == 0 || height == 0) { + throw new IllegalArgumentException("Invalid size: " + width + "x" + height); + } + if (width == this.width && height == this.height) { + return; + } + this.width = width; + this.height = height; + + // Bind our framebuffer. + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId); + GlUtil.checkNoGLES2Error("glBindFramebuffer"); + + // Allocate texture. + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, pixelFormat, width, height, 0, pixelFormat, + GLES20.GL_UNSIGNED_BYTE, null); + + // Check that the framebuffer is in a good state. + final int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER); + if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) { + throw new IllegalStateException("Framebuffer not complete, status: " + status); + } + + // Restore normal framebuffer. + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getFrameBufferId() { + return frameBufferId; + } + + public int getTextureId() { + return textureId; + } + + /** + * Release texture and framebuffer. An EGLContext must be bound on the current thread when calling + * this function. This object should not be used after this call. + */ + public void release() { + GLES20.glDeleteTextures(1, new int[] {textureId}, 0); + GLES20.glDeleteFramebuffers(1, new int[] {frameBufferId}, 0); + width = 0; + height = 0; + } +} diff --git a/talk/libjingle.gyp b/talk/libjingle.gyp index 2d4a27a80f..abb601d04f 100755 --- a/talk/libjingle.gyp +++ b/talk/libjingle.gyp @@ -149,6 +149,7 @@ 'app/webrtc/java/android/org/webrtc/GlRectDrawer.java', 'app/webrtc/java/android/org/webrtc/GlShader.java', 'app/webrtc/java/android/org/webrtc/GlUtil.java', + 'app/webrtc/java/android/org/webrtc/GlTextureFrameBuffer.java', 'app/webrtc/java/android/org/webrtc/RendererCommon.java', 'app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java', 'app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java',