From edc4bd5be13297ade9dc3f4a1f90af5898537b78 Mon Sep 17 00:00:00 2001 From: huangdarwin Date: Thu, 4 Nov 2021 13:58:55 +0000 Subject: [PATCH] GL: Misc GL refactoring. * Remove GlUtil.Program String[] constructor to unify and just use the String constructor. * Add getAttributeArrayLocationAndEnable() to simplify things a tiny bit. * Increase usage of constant values. PiperOrigin-RevId: 407570340 --- .../androidx/media3/common/util/GlUtil.java | 30 +++++----- .../video/VideoDecoderGLSurfaceView.java | 19 +++--- .../video/spherical/ProjectionRenderer.java | 59 ++++++++----------- .../TransformerTranscodingVideoRenderer.java | 21 ++++--- 4 files changed, 60 insertions(+), 69 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java b/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java index cfa6092c9e..afddf6c956 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/GlUtil.java @@ -26,7 +26,6 @@ import android.opengl.EGLDisplay; import android.opengl.EGLSurface; import android.opengl.GLES11Ext; import android.opengl.GLES20; -import android.text.TextUtils; import androidx.annotation.DoNotInline; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; @@ -88,18 +87,6 @@ public final class GlUtil { this(loadAsset(context, vertexShaderFilePath), loadAsset(context, fragmentShaderFilePath)); } - /** - * Compiles a GL shader program from vertex and fragment shader GLSL GLES20 code. - * - * @param vertexShaderGlsl The vertex shader program as arrays of strings. Strings are joined by - * adding a new line character in between each of them. - * @param fragmentShaderGlsl The fragment shader program as arrays of strings. Strings are - * joined by adding a new line character in between each of them. - */ - public Program(String[] vertexShaderGlsl, String[] fragmentShaderGlsl) { - this(TextUtils.join("\n", vertexShaderGlsl), TextUtils.join("\n", fragmentShaderGlsl)); - } - /** Uses the program. */ public void use() { // Link and check for errors. @@ -120,8 +107,19 @@ public final class GlUtil { GLES20.glDeleteProgram(programId); } + /** + * Returns the location of an {@link Attribute}, which has been enabled as a vertex attribute + * array. + */ + public int getAttributeArrayLocationAndEnable(String attributeName) { + int location = getAttributeLocation(attributeName); + GLES20.glEnableVertexAttribArray(location); + checkGlError(); + return location; + } + /** Returns the location of an {@link Attribute}. */ - public int getAttribLocation(String attributeName) { + private int getAttributeLocation(String attributeName) { return GLES20.glGetAttribLocation(programId, attributeName); } @@ -135,7 +133,7 @@ public final class GlUtil { int[] attributeCount = new int[1]; GLES20.glGetProgramiv(programId, GLES20.GL_ACTIVE_ATTRIBUTES, attributeCount, 0); if (attributeCount[0] != 2) { - throw new IllegalStateException("Expected two attributes."); + throw new IllegalStateException("Expected two attributes but found " + attributeCount[0]); } Attribute[] attributes = new Attribute[attributeCount[0]]; @@ -170,7 +168,7 @@ public final class GlUtil { GLES20.glGetActiveAttrib( programId, index, length[0], ignore, 0, size, 0, type, 0, nameBytes, 0); String name = new String(nameBytes, 0, strlen(nameBytes)); - int location = getAttribLocation(name); + int location = getAttributeLocation(name); return new Attribute(name, index, location); } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoDecoderGLSurfaceView.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoDecoderGLSurfaceView.java index 056d8c93b5..903c2b7478 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoDecoderGLSurfaceView.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoDecoderGLSurfaceView.java @@ -169,8 +169,7 @@ public final class VideoDecoderGLSurfaceView extends GLSurfaceView public void onSurfaceCreated(GL10 unused, EGLConfig config) { program = new GlUtil.Program(VERTEX_SHADER, FRAGMENT_SHADER); program.use(); - int posLocation = program.getAttribLocation("in_pos"); - GLES20.glEnableVertexAttribArray(posLocation); + int posLocation = program.getAttributeArrayLocationAndEnable("in_pos"); GLES20.glVertexAttribPointer( posLocation, 2, @@ -178,13 +177,9 @@ public final class VideoDecoderGLSurfaceView extends GLSurfaceView /* normalized= */ false, /* stride= */ 0, TEXTURE_VERTICES); - texLocations[0] = program.getAttribLocation("in_tc_y"); - GLES20.glEnableVertexAttribArray(texLocations[0]); - texLocations[1] = program.getAttribLocation("in_tc_u"); - GLES20.glEnableVertexAttribArray(texLocations[1]); - texLocations[2] = program.getAttribLocation("in_tc_v"); - GLES20.glEnableVertexAttribArray(texLocations[2]); - GlUtil.checkGlError(); + texLocations[0] = program.getAttributeArrayLocationAndEnable("in_tc_y"); + texLocations[1] = program.getAttributeArrayLocationAndEnable("in_tc_u"); + texLocations[2] = program.getAttributeArrayLocationAndEnable("in_tc_v"); colorMatrixLocation = program.getUniformLocation("mColorConversion"); GlUtil.checkGlError(); setupTextures(); @@ -257,9 +252,9 @@ public final class VideoDecoderGLSurfaceView extends GLSurfaceView int[] widths = new int[3]; widths[0] = outputBuffer.width; - // TODO: Handle streams where chroma channels are not stored at half width and height - // compared to luma channel. See [Internal: b/142097774]. - // U and V planes are being stored at half width compared to Y. + // TODO(b/142097774): Handle streams where chroma channels are not stored at half width and + // height compared to the luma channel. U and V planes are being stored at half width compared + // to Y. widths[1] = widths[2] = (widths[0] + 1) / 2; for (int i = 0; i < 3; i++) { // Set cropping of stride if either width or stride has changed. diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/spherical/ProjectionRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/spherical/ProjectionRenderer.java index dea534f0e4..8fe10ac16a 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/spherical/ProjectionRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/spherical/ProjectionRenderer.java @@ -46,33 +46,27 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } // Basic vertex & fragment shaders to render a mesh with 3D position & 2D texture data. - private static final String[] VERTEX_SHADER_CODE = - new String[] { - "uniform mat4 uMvpMatrix;", - "uniform mat3 uTexMatrix;", - "attribute vec4 aPosition;", - "attribute vec2 aTexCoords;", - "varying vec2 vTexCoords;", - - // Standard transformation. - "void main() {", - " gl_Position = uMvpMatrix * aPosition;", - " vTexCoords = (uTexMatrix * vec3(aTexCoords, 1)).xy;", - "}" - }; - private static final String[] FRAGMENT_SHADER_CODE = - new String[] { - // This is required since the texture data is GL_TEXTURE_EXTERNAL_OES. - "#extension GL_OES_EGL_image_external : require", - "precision mediump float;", - - // Standard texture rendering shader. - "uniform samplerExternalOES uTexture;", - "varying vec2 vTexCoords;", - "void main() {", - " gl_FragColor = texture2D(uTexture, vTexCoords);", - "}" - }; + private static final String VERTEX_SHADER = + "uniform mat4 uMvpMatrix;\n" + + "uniform mat3 uTexMatrix;\n" + + "attribute vec4 aPosition;\n" + + "attribute vec2 aTexCoords;\n" + + "varying vec2 vTexCoords;\n" + + "// Standard transformation.\n" + + "void main() {\n" + + " gl_Position = uMvpMatrix * aPosition;\n" + + " vTexCoords = (uTexMatrix * vec3(aTexCoords, 1)).xy;\n" + + "}\n"; + private static final String FRAGMENT_SHADER = + "// This is required since the texture data is GL_TEXTURE_EXTERNAL_OES.\n" + + "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "// Standard texture rendering shader.\n" + + "uniform samplerExternalOES uTexture;\n" + + "varying vec2 vTexCoords;\n" + + "void main() {\n" + + " gl_FragColor = texture2D(uTexture, vTexCoords);\n" + + "}\n"; // Texture transform matrices. private static final float[] TEX_MATRIX_WHOLE = { @@ -121,11 +115,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** Initializes of the GL components. */ /* package */ void init() { - program = new GlUtil.Program(VERTEX_SHADER_CODE, FRAGMENT_SHADER_CODE); + program = new GlUtil.Program(VERTEX_SHADER, FRAGMENT_SHADER); mvpMatrixHandle = program.getUniformLocation("uMvpMatrix"); uTexMatrixHandle = program.getUniformLocation("uTexMatrix"); - positionHandle = program.getAttribLocation("aPosition"); - texCoordsHandle = program.getAttribLocation("aTexCoords"); + positionHandle = program.getAttributeArrayLocationAndEnable("aPosition"); + texCoordsHandle = program.getAttributeArrayLocationAndEnable("aTexCoords"); textureHandle = program.getUniformLocation("uTexture"); } @@ -148,10 +142,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; checkNotNull(program).use(); checkGlError(); - GLES20.glEnableVertexAttribArray(positionHandle); - GLES20.glEnableVertexAttribArray(texCoordsHandle); - checkGlError(); - float[] texMatrix; if (stereoMode == C.STEREO_MODE_TOP_BOTTOM) { texMatrix = rightEye ? TEX_MATRIX_BOTTOM : TEX_MATRIX_TOP; @@ -162,6 +152,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } GLES20.glUniformMatrix3fv(uTexMatrixHandle, 1, false, texMatrix, 0); + // TODO(b/205002913): Update to use GlUtil.Uniform.bind(). GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerTranscodingVideoRenderer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerTranscodingVideoRenderer.java index 9896b88517..2ca09e37a6 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerTranscodingVideoRenderer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerTranscodingVideoRenderer.java @@ -56,6 +56,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private static final String TAG = "TransformerTranscodingVideoRenderer"; + // Predefined shader values. + private static final String VERTEX_SHADER_FILE_PATH = "shaders/blit_vertex_shader.glsl"; + private static final String FRAGMENT_SHADER_FILE_PATH = + "shaders/copy_external_fragment_shader.glsl"; + private static final int EXPECTED_NUMBER_OF_ATTRIBUTES = 2; + private static final int EXPECTED_NUMBER_OF_UNIFORMS = 2; + private final Context context; private final DecoderInputBuffer decoderInputBuffer; @@ -231,18 +238,16 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; decoderTextureId = GlUtil.createExternalTexture(); GlUtil.Program copyProgram; try { - copyProgram = - new GlUtil.Program( - context, - /* vertexShaderFilePath= */ "shaders/blit_vertex_shader.glsl", - /* fragmentShaderFilePath= */ "shaders/copy_external_fragment_shader.glsl"); + copyProgram = new GlUtil.Program(context, VERTEX_SHADER_FILE_PATH, FRAGMENT_SHADER_FILE_PATH); } catch (IOException e) { throw new IllegalStateException(e); } copyProgram.use(); GlUtil.Attribute[] copyAttributes = copyProgram.getAttributes(); - checkState(copyAttributes.length == 2, "Expected program to have two vertex attributes."); + checkState( + copyAttributes.length == EXPECTED_NUMBER_OF_ATTRIBUTES, + "Expected program to have " + EXPECTED_NUMBER_OF_ATTRIBUTES + " vertex attributes."); for (GlUtil.Attribute copyAttribute : copyAttributes) { if (copyAttribute.name.equals("a_position")) { copyAttribute.setBuffer( @@ -268,7 +273,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; copyAttribute.bind(); } GlUtil.Uniform[] copyUniforms = copyProgram.getUniforms(); - checkState(copyUniforms.length == 2, "Expected program to have two uniforms."); + checkState( + copyUniforms.length == EXPECTED_NUMBER_OF_UNIFORMS, + "Expected program to have " + EXPECTED_NUMBER_OF_UNIFORMS + " uniforms."); for (GlUtil.Uniform copyUniform : copyUniforms) { if (copyUniform.name.equals("tex_sampler")) { copyUniform.setSamplerTexId(decoderTextureId, 0);