1 /* 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 package org.webrtc; 12 13 import android.opengl.GLES20; 14 15 /** 16 * Helper class for handling OpenGL framebuffer with only color attachment and no depth or stencil 17 * buffer. Intended for simple tasks such as texture copy, texture downscaling, and texture color 18 * conversion. This class is not thread safe and must be used by a thread with an active GL context. 19 */ 20 // TODO(magjed): Add unittests for this class. 21 public class GlTextureFrameBuffer { 22 private final int pixelFormat; 23 private int frameBufferId; 24 private int textureId; 25 private int width; 26 private int height; 27 28 /** 29 * Generate texture and framebuffer resources. An EGLContext must be bound on the current thread 30 * when calling this function. The framebuffer is not complete until setSize() is called. 31 */ GlTextureFrameBuffer(int pixelFormat)32 public GlTextureFrameBuffer(int pixelFormat) { 33 switch (pixelFormat) { 34 case GLES20.GL_LUMINANCE: 35 case GLES20.GL_RGB: 36 case GLES20.GL_RGBA: 37 this.pixelFormat = pixelFormat; 38 break; 39 default: 40 throw new IllegalArgumentException("Invalid pixel format: " + pixelFormat); 41 } 42 this.width = 0; 43 this.height = 0; 44 } 45 46 /** 47 * (Re)allocate texture. Will do nothing if the requested size equals the current size. An 48 * EGLContext must be bound on the current thread when calling this function. Must be called at 49 * least once before using the framebuffer. May be called multiple times to change size. 50 */ setSize(int width, int height)51 public void setSize(int width, int height) { 52 if (width <= 0 || height <= 0) { 53 throw new IllegalArgumentException("Invalid size: " + width + "x" + height); 54 } 55 if (width == this.width && height == this.height) { 56 return; 57 } 58 this.width = width; 59 this.height = height; 60 // Lazy allocation the first time setSize() is called. 61 if (textureId == 0) { 62 textureId = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); 63 } 64 if (frameBufferId == 0) { 65 final int frameBuffers[] = new int[1]; 66 GLES20.glGenFramebuffers(1, frameBuffers, 0); 67 frameBufferId = frameBuffers[0]; 68 } 69 70 // Allocate texture. 71 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 72 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); 73 GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, pixelFormat, width, height, 0, pixelFormat, 74 GLES20.GL_UNSIGNED_BYTE, null); 75 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); 76 GlUtil.checkNoGLES2Error("GlTextureFrameBuffer setSize"); 77 78 // Attach the texture to the framebuffer as color attachment. 79 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId); 80 GLES20.glFramebufferTexture2D( 81 GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureId, 0); 82 83 // Check that the framebuffer is in a good state. 84 final int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER); 85 if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) { 86 throw new IllegalStateException("Framebuffer not complete, status: " + status); 87 } 88 89 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); 90 } 91 getWidth()92 public int getWidth() { 93 return width; 94 } 95 getHeight()96 public int getHeight() { 97 return height; 98 } 99 100 /** Gets the OpenGL frame buffer id. This value is only valid after setSize() has been called. */ getFrameBufferId()101 public int getFrameBufferId() { 102 return frameBufferId; 103 } 104 105 /** Gets the OpenGL texture id. This value is only valid after setSize() has been called. */ getTextureId()106 public int getTextureId() { 107 return textureId; 108 } 109 110 /** 111 * Release texture and framebuffer. An EGLContext must be bound on the current thread when calling 112 * this function. This object should not be used after this call. 113 */ release()114 public void release() { 115 GLES20.glDeleteTextures(1, new int[] {textureId}, 0); 116 textureId = 0; 117 GLES20.glDeleteFramebuffers(1, new int[] {frameBufferId}, 0); 118 frameBufferId = 0; 119 width = 0; 120 height = 0; 121 } 122 } 123