| /* | |
| * Copyright 2015 The WebRTC project authors. All Rights Reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| 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. This class is not thread safe and must be used by a thread with an active GL context. | |
| */ | |
| // TODO(magjed): Add unittests for this class. | |
| public class GlTextureFrameBuffer { | |
| private final int pixelFormat; | |
| private int frameBufferId; | |
| private int textureId; | |
| 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); | |
| } | |
| this.width = 0; | |
| this.height = 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; | |
| // Lazy allocation the first time setSize() is called. | |
| if (textureId == 0) { | |
| textureId = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); | |
| } | |
| if (frameBufferId == 0) { | |
| final int frameBuffers[] = new int[1]; | |
| GLES20.glGenFramebuffers(1, frameBuffers, 0); | |
| frameBufferId = frameBuffers[0]; | |
| } | |
| // 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); | |
| GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); | |
| GlUtil.checkNoGLES2Error("GlTextureFrameBuffer setSize"); | |
| // Attach the texture to the framebuffer as color attachment. | |
| GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId); | |
| GLES20.glFramebufferTexture2D( | |
| GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureId, 0); | |
| // 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); | |
| } | |
| GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); | |
| } | |
| public int getWidth() { | |
| return width; | |
| } | |
| public int getHeight() { | |
| return height; | |
| } | |
| /** Gets the OpenGL frame buffer id. This value is only valid after setSize() has been called. */ | |
| public int getFrameBufferId() { | |
| return frameBufferId; | |
| } | |
| /** Gets the OpenGL texture id. This value is only valid after setSize() has been called. */ | |
| 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); | |
| textureId = 0; | |
| GLES20.glDeleteFramebuffers(1, new int[] {frameBufferId}, 0); | |
| frameBufferId = 0; | |
| width = 0; | |
| height = 0; | |
| } | |
| } |