GlRectDrawer.java revision 7afc12fe91e97a3d68de3768a73f3604e5651504
159a677ada27c660e9cd7486f0d702753dbeb6d39magjed/* 259a677ada27c660e9cd7486f0d702753dbeb6d39magjed * libjingle 359a677ada27c660e9cd7486f0d702753dbeb6d39magjed * Copyright 2015 Google Inc. 459a677ada27c660e9cd7486f0d702753dbeb6d39magjed * 559a677ada27c660e9cd7486f0d702753dbeb6d39magjed * Redistribution and use in source and binary forms, with or without 659a677ada27c660e9cd7486f0d702753dbeb6d39magjed * modification, are permitted provided that the following conditions are met: 759a677ada27c660e9cd7486f0d702753dbeb6d39magjed * 859a677ada27c660e9cd7486f0d702753dbeb6d39magjed * 1. Redistributions of source code must retain the above copyright notice, 959a677ada27c660e9cd7486f0d702753dbeb6d39magjed * this list of conditions and the following disclaimer. 1059a677ada27c660e9cd7486f0d702753dbeb6d39magjed * 2. Redistributions in binary form must reproduce the above copyright notice, 1159a677ada27c660e9cd7486f0d702753dbeb6d39magjed * this list of conditions and the following disclaimer in the documentation 1259a677ada27c660e9cd7486f0d702753dbeb6d39magjed * and/or other materials provided with the distribution. 1359a677ada27c660e9cd7486f0d702753dbeb6d39magjed * 3. The name of the author may not be used to endorse or promote products 1459a677ada27c660e9cd7486f0d702753dbeb6d39magjed * derived from this software without specific prior written permission. 1559a677ada27c660e9cd7486f0d702753dbeb6d39magjed * 1659a677ada27c660e9cd7486f0d702753dbeb6d39magjed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 1759a677ada27c660e9cd7486f0d702753dbeb6d39magjed * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1859a677ada27c660e9cd7486f0d702753dbeb6d39magjed * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 1959a677ada27c660e9cd7486f0d702753dbeb6d39magjed * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2059a677ada27c660e9cd7486f0d702753dbeb6d39magjed * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2159a677ada27c660e9cd7486f0d702753dbeb6d39magjed * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2259a677ada27c660e9cd7486f0d702753dbeb6d39magjed * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2359a677ada27c660e9cd7486f0d702753dbeb6d39magjed * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2459a677ada27c660e9cd7486f0d702753dbeb6d39magjed * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2559a677ada27c660e9cd7486f0d702753dbeb6d39magjed * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2659a677ada27c660e9cd7486f0d702753dbeb6d39magjed */ 2759a677ada27c660e9cd7486f0d702753dbeb6d39magjed 2859a677ada27c660e9cd7486f0d702753dbeb6d39magjedpackage org.webrtc; 2959a677ada27c660e9cd7486f0d702753dbeb6d39magjed 3059a677ada27c660e9cd7486f0d702753dbeb6d39magjedimport android.opengl.GLES11Ext; 3159a677ada27c660e9cd7486f0d702753dbeb6d39magjedimport android.opengl.GLES20; 3259a677ada27c660e9cd7486f0d702753dbeb6d39magjed 3359a677ada27c660e9cd7486f0d702753dbeb6d39magjedimport org.webrtc.GlShader; 3459a677ada27c660e9cd7486f0d702753dbeb6d39magjedimport org.webrtc.GlUtil; 3559a677ada27c660e9cd7486f0d702753dbeb6d39magjed 3659a677ada27c660e9cd7486f0d702753dbeb6d39magjedimport java.nio.ByteBuffer; 3759a677ada27c660e9cd7486f0d702753dbeb6d39magjedimport java.nio.FloatBuffer; 3859a677ada27c660e9cd7486f0d702753dbeb6d39magjedimport java.util.Arrays; 39ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvertimport java.util.IdentityHashMap; 40ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvertimport java.util.Map; 4159a677ada27c660e9cd7486f0d702753dbeb6d39magjed 4259a677ada27c660e9cd7486f0d702753dbeb6d39magjed/** 4359a677ada27c660e9cd7486f0d702753dbeb6d39magjed * Helper class to draw a quad that covers the entire viewport. Rotation, mirror, and cropping is 4459a677ada27c660e9cd7486f0d702753dbeb6d39magjed * specified using a 4x4 texture coordinate transform matrix. The frame input can either be an OES 4559a677ada27c660e9cd7486f0d702753dbeb6d39magjed * texture or YUV textures in I420 format. The GL state must be preserved between draw calls, this 4659a677ada27c660e9cd7486f0d702753dbeb6d39magjed * is intentional to maximize performance. The function release() must be called manually to free 4759a677ada27c660e9cd7486f0d702753dbeb6d39magjed * the resources held by this object. 4859a677ada27c660e9cd7486f0d702753dbeb6d39magjed */ 4959a677ada27c660e9cd7486f0d702753dbeb6d39magjedpublic class GlRectDrawer { 5059a677ada27c660e9cd7486f0d702753dbeb6d39magjed // Simple vertex shader, used for both YUV and OES. 5159a677ada27c660e9cd7486f0d702753dbeb6d39magjed private static final String VERTEX_SHADER_STRING = 52ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert "varying vec2 interp_tc;\n" 5359a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "attribute vec4 in_pos;\n" 5459a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "attribute vec4 in_tc;\n" 5559a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "\n" 5659a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "uniform mat4 texMatrix;\n" 5759a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "\n" 5859a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "void main() {\n" 5959a677ada27c660e9cd7486f0d702753dbeb6d39magjed + " gl_Position = in_pos;\n" 6059a677ada27c660e9cd7486f0d702753dbeb6d39magjed + " interp_tc = (texMatrix * in_tc).xy;\n" 6159a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "}\n"; 6259a677ada27c660e9cd7486f0d702753dbeb6d39magjed 6359a677ada27c660e9cd7486f0d702753dbeb6d39magjed private static final String YUV_FRAGMENT_SHADER_STRING = 64ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert "precision mediump float;\n" 6559a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "varying vec2 interp_tc;\n" 6659a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "\n" 6759a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "uniform sampler2D y_tex;\n" 6859a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "uniform sampler2D u_tex;\n" 6959a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "uniform sampler2D v_tex;\n" 7059a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "\n" 7159a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "void main() {\n" 7259a677ada27c660e9cd7486f0d702753dbeb6d39magjed // CSC according to http://www.fourcc.org/fccyvrgb.php 7359a677ada27c660e9cd7486f0d702753dbeb6d39magjed + " float y = texture2D(y_tex, interp_tc).r;\n" 7459a677ada27c660e9cd7486f0d702753dbeb6d39magjed + " float u = texture2D(u_tex, interp_tc).r - 0.5;\n" 7559a677ada27c660e9cd7486f0d702753dbeb6d39magjed + " float v = texture2D(v_tex, interp_tc).r - 0.5;\n" 7659a677ada27c660e9cd7486f0d702753dbeb6d39magjed + " gl_FragColor = vec4(y + 1.403 * v, " 7759a677ada27c660e9cd7486f0d702753dbeb6d39magjed + " y - 0.344 * u - 0.714 * v, " 7859a677ada27c660e9cd7486f0d702753dbeb6d39magjed + " y + 1.77 * u, 1);\n" 7959a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "}\n"; 8059a677ada27c660e9cd7486f0d702753dbeb6d39magjed 81ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert private static final String RGB_FRAGMENT_SHADER_STRING = 82ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert "precision mediump float;\n" 83ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert + "varying vec2 interp_tc;\n" 84ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert + "\n" 85ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert + "uniform sampler2D rgb_tex;\n" 86ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert + "\n" 87ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert + "void main() {\n" 88ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert + " gl_FragColor = texture2D(rgb_tex, interp_tc);\n" 89ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert + "}\n"; 90ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert 9159a677ada27c660e9cd7486f0d702753dbeb6d39magjed private static final String OES_FRAGMENT_SHADER_STRING = 92ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert "#extension GL_OES_EGL_image_external : require\n" 9359a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "precision mediump float;\n" 9459a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "varying vec2 interp_tc;\n" 9559a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "\n" 9659a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "uniform samplerExternalOES oes_tex;\n" 9759a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "\n" 9859a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "void main() {\n" 9959a677ada27c660e9cd7486f0d702753dbeb6d39magjed + " gl_FragColor = texture2D(oes_tex, interp_tc);\n" 10059a677ada27c660e9cd7486f0d702753dbeb6d39magjed + "}\n"; 10159a677ada27c660e9cd7486f0d702753dbeb6d39magjed 10259a677ada27c660e9cd7486f0d702753dbeb6d39magjed private static final FloatBuffer FULL_RECTANGLE_BUF = 10359a677ada27c660e9cd7486f0d702753dbeb6d39magjed GlUtil.createFloatBuffer(new float[] { 10459a677ada27c660e9cd7486f0d702753dbeb6d39magjed -1.0f, -1.0f, // Bottom left. 10559a677ada27c660e9cd7486f0d702753dbeb6d39magjed 1.0f, -1.0f, // Bottom right. 10659a677ada27c660e9cd7486f0d702753dbeb6d39magjed -1.0f, 1.0f, // Top left. 10759a677ada27c660e9cd7486f0d702753dbeb6d39magjed 1.0f, 1.0f, // Top right. 10859a677ada27c660e9cd7486f0d702753dbeb6d39magjed }); 10959a677ada27c660e9cd7486f0d702753dbeb6d39magjed 11059a677ada27c660e9cd7486f0d702753dbeb6d39magjed private static final FloatBuffer FULL_RECTANGLE_TEX_BUF = 11159a677ada27c660e9cd7486f0d702753dbeb6d39magjed GlUtil.createFloatBuffer(new float[] { 11259a677ada27c660e9cd7486f0d702753dbeb6d39magjed 0.0f, 0.0f, // Bottom left. 11359a677ada27c660e9cd7486f0d702753dbeb6d39magjed 1.0f, 0.0f, // Bottom right. 11459a677ada27c660e9cd7486f0d702753dbeb6d39magjed 0.0f, 1.0f, // Top left. 11559a677ada27c660e9cd7486f0d702753dbeb6d39magjed 1.0f, 1.0f // Top right. 11659a677ada27c660e9cd7486f0d702753dbeb6d39magjed }); 11759a677ada27c660e9cd7486f0d702753dbeb6d39magjed 118ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert // The keys are one of the fragments shaders above. 119ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert private final Map<String, GlShader> shaders = new IdentityHashMap<String, GlShader>(); 12059a677ada27c660e9cd7486f0d702753dbeb6d39magjed private GlShader currentShader; 12159a677ada27c660e9cd7486f0d702753dbeb6d39magjed private float[] currentTexMatrix; 12259a677ada27c660e9cd7486f0d702753dbeb6d39magjed private int texMatrixLocation; 1237afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert // Intermediate copy buffer for uploading yuv frames that are not packed, i.e. stride > width. 1247afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert // TODO(magjed): Investigate when GL_UNPACK_ROW_LENGTH is available, or make a custom shader that 1257afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert // handles stride and compare performance with intermediate copy. 1267afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert private ByteBuffer copyBuffer; 1277afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert 1287afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert /** 1297afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert * Upload |planes| into |outputYuvTextures|, taking stride into consideration. |outputYuvTextures| 1307afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert * must have been generated in advance. 1317afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert */ 1327afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert public void uploadYuvData( 1337afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert int[] outputYuvTextures, int width, int height, int[] strides, ByteBuffer[] planes) { 1347afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert // Make a first pass to see if we need a temporary copy buffer. 1357afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert int copyCapacityNeeded = 0; 1367afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert for (int i = 0; i < 3; ++i) { 1377afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert final int planeWidth = (i == 0) ? width : width / 2; 1387afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert final int planeHeight = (i == 0) ? height : height / 2; 1397afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert if (strides[i] > planeWidth) { 1407afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert copyCapacityNeeded = Math.max(copyCapacityNeeded, planeWidth * planeHeight); 1417afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert } 1427afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert } 1437afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert // Allocate copy buffer if necessary. 1447afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert if (copyCapacityNeeded > 0 1457afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert && (copyBuffer == null || copyBuffer.capacity() < copyCapacityNeeded)) { 1467afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert copyBuffer = ByteBuffer.allocateDirect(copyCapacityNeeded); 1477afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert } 1487afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert // Upload each plane. 1497afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert for (int i = 0; i < 3; ++i) { 1507afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); 1517afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, outputYuvTextures[i]); 1527afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert final int planeWidth = (i == 0) ? width : width / 2; 1537afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert final int planeHeight = (i == 0) ? height : height / 2; 1547afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert // GLES only accepts packed data, i.e. stride == planeWidth. 1557afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert final ByteBuffer packedByteBuffer; 1567afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert if (strides[i] == planeWidth) { 1577afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert // Input is packed already. 1587afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert packedByteBuffer = planes[i]; 1597afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert } else { 1607afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert VideoRenderer.nativeCopyPlane( 1617afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert planes[i], planeWidth, planeHeight, strides[i], copyBuffer, planeWidth); 1627afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert packedByteBuffer = copyBuffer; 1637afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert } 1647afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, planeWidth, planeHeight, 0, 1657afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, packedByteBuffer); 1667afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert } 1677afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert } 16859a677ada27c660e9cd7486f0d702753dbeb6d39magjed 16959a677ada27c660e9cd7486f0d702753dbeb6d39magjed /** 17059a677ada27c660e9cd7486f0d702753dbeb6d39magjed * Draw an OES texture frame with specified texture transformation matrix. Required resources are 17159a677ada27c660e9cd7486f0d702753dbeb6d39magjed * allocated at the first call to this function. 17259a677ada27c660e9cd7486f0d702753dbeb6d39magjed */ 17359a677ada27c660e9cd7486f0d702753dbeb6d39magjed public void drawOes(int oesTextureId, float[] texMatrix) { 174ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert prepareShader(OES_FRAGMENT_SHADER_STRING); 17559a677ada27c660e9cd7486f0d702753dbeb6d39magjed // updateTexImage() may be called from another thread in another EGL context, so we need to 17659a677ada27c660e9cd7486f0d702753dbeb6d39magjed // bind/unbind the texture in each draw call so that GLES understads it's a new texture. 17759a677ada27c660e9cd7486f0d702753dbeb6d39magjed GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, oesTextureId); 17859a677ada27c660e9cd7486f0d702753dbeb6d39magjed drawRectangle(texMatrix); 17959a677ada27c660e9cd7486f0d702753dbeb6d39magjed GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); 18059a677ada27c660e9cd7486f0d702753dbeb6d39magjed } 18159a677ada27c660e9cd7486f0d702753dbeb6d39magjed 18259a677ada27c660e9cd7486f0d702753dbeb6d39magjed /** 183ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert * Draw a RGB(A) texture frame with specified texture transformation matrix. Required resources 184ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert * are allocated at the first call to this function. 185ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert */ 186ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert public void drawRgb(int textureId, float[] texMatrix) { 187ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert prepareShader(RGB_FRAGMENT_SHADER_STRING); 188ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); 189ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert drawRectangle(texMatrix); 190ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert // Unbind the texture as a precaution. 191ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); 192ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert } 193ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert 194ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert /** 19559a677ada27c660e9cd7486f0d702753dbeb6d39magjed * Draw a YUV frame with specified texture transformation matrix. Required resources are 19659a677ada27c660e9cd7486f0d702753dbeb6d39magjed * allocated at the first call to this function. 19759a677ada27c660e9cd7486f0d702753dbeb6d39magjed */ 1987afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert public void drawYuv(int[] yuvTextures, float[] texMatrix) { 199ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert prepareShader(YUV_FRAGMENT_SHADER_STRING); 20059a677ada27c660e9cd7486f0d702753dbeb6d39magjed // Bind the textures. 20159a677ada27c660e9cd7486f0d702753dbeb6d39magjed for (int i = 0; i < 3; ++i) { 20259a677ada27c660e9cd7486f0d702753dbeb6d39magjed GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); 20359a677ada27c660e9cd7486f0d702753dbeb6d39magjed GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yuvTextures[i]); 20459a677ada27c660e9cd7486f0d702753dbeb6d39magjed } 20559a677ada27c660e9cd7486f0d702753dbeb6d39magjed drawRectangle(texMatrix); 206ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert // Unbind the textures as a precaution.. 207ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert for (int i = 0; i < 3; ++i) { 208ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); 209ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); 210ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert } 21159a677ada27c660e9cd7486f0d702753dbeb6d39magjed } 21259a677ada27c660e9cd7486f0d702753dbeb6d39magjed 21359a677ada27c660e9cd7486f0d702753dbeb6d39magjed private void drawRectangle(float[] texMatrix) { 21459a677ada27c660e9cd7486f0d702753dbeb6d39magjed // Try avoid uploading the texture if possible. 21559a677ada27c660e9cd7486f0d702753dbeb6d39magjed if (!Arrays.equals(currentTexMatrix, texMatrix)) { 21659a677ada27c660e9cd7486f0d702753dbeb6d39magjed currentTexMatrix = texMatrix.clone(); 21759a677ada27c660e9cd7486f0d702753dbeb6d39magjed // Copy the texture transformation matrix over. 21859a677ada27c660e9cd7486f0d702753dbeb6d39magjed GLES20.glUniformMatrix4fv(texMatrixLocation, 1, false, texMatrix, 0); 21959a677ada27c660e9cd7486f0d702753dbeb6d39magjed } 22059a677ada27c660e9cd7486f0d702753dbeb6d39magjed // Draw quad. 22159a677ada27c660e9cd7486f0d702753dbeb6d39magjed GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 22259a677ada27c660e9cd7486f0d702753dbeb6d39magjed } 22359a677ada27c660e9cd7486f0d702753dbeb6d39magjed 224ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert private void prepareShader(String fragmentShader) { 225ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert // Lazy allocation. 226ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert if (!shaders.containsKey(fragmentShader)) { 227ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert final GlShader shader = new GlShader(VERTEX_SHADER_STRING, fragmentShader); 228ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert shaders.put(fragmentShader, shader); 229ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert shader.useProgram(); 230ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert // Initialize fragment shader uniform values. 231ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert if (fragmentShader == YUV_FRAGMENT_SHADER_STRING) { 232ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GLES20.glUniform1i(shader.getUniformLocation("y_tex"), 0); 233ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GLES20.glUniform1i(shader.getUniformLocation("u_tex"), 1); 234ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GLES20.glUniform1i(shader.getUniformLocation("v_tex"), 2); 235ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert } else if (fragmentShader == RGB_FRAGMENT_SHADER_STRING) { 236ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GLES20.glUniform1i(shader.getUniformLocation("rgb_tex"), 0); 237ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert } else if (fragmentShader == OES_FRAGMENT_SHADER_STRING) { 238ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GLES20.glUniform1i(shader.getUniformLocation("oes_tex"), 0); 239ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert } else { 240ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert throw new IllegalStateException("Unknown fragment shader: " + fragmentShader); 241ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert } 242ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GlUtil.checkNoGLES2Error("Initialize fragment shader uniform values."); 243ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert // Initialize vertex shader attributes. 244ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert shader.setVertexAttribArray("in_pos", 2, FULL_RECTANGLE_BUF); 245ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert shader.setVertexAttribArray("in_tc", 2, FULL_RECTANGLE_TEX_BUF); 246ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert } 247ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert 248ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert // Update GLES state if shader is not already current. 249ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert final GlShader shader = shaders.get(fragmentShader); 250ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert if (currentShader != shader) { 251ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert currentShader = shader; 252ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert shader.useProgram(); 253ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 254ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert currentTexMatrix = null; 255ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert texMatrixLocation = shader.getUniformLocation("texMatrix"); 256ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert } 257ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert } 258ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert 25959a677ada27c660e9cd7486f0d702753dbeb6d39magjed /** 26059a677ada27c660e9cd7486f0d702753dbeb6d39magjed * Release all GLES resources. This needs to be done manually, otherwise the resources are leaked. 26159a677ada27c660e9cd7486f0d702753dbeb6d39magjed */ 26259a677ada27c660e9cd7486f0d702753dbeb6d39magjed public void release() { 263ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert for (GlShader shader : shaders.values()) { 264ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert shader.release(); 26559a677ada27c660e9cd7486f0d702753dbeb6d39magjed } 266ed4224fbdaca23a9ba593d07d6809a0943f73528Magnus Jedvert shaders.clear(); 2677afc12fe91e97a3d68de3768a73f3604e5651504Magnus Jedvert copyBuffer = null; 26859a677ada27c660e9cd7486f0d702753dbeb6d39magjed } 26959a677ada27c660e9cd7486f0d702753dbeb6d39magjed} 270