*** Original commit ***

Simplify GL program handling.

***

PiperOrigin-RevId: 400970170
This commit is contained in:
claincly 2021-10-05 14:34:04 +01:00 committed by bachinger
parent 80d365163d
commit 3eda590c87
5 changed files with 168 additions and 229 deletions

View File

@ -15,8 +15,6 @@
*/ */
package com.google.android.exoplayer2.gldemo; package com.google.android.exoplayer2.gldemo;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -28,6 +26,7 @@ import android.opengl.GLES20;
import android.opengl.GLUtils; import android.opengl.GLUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.GlUtil; import com.google.android.exoplayer2.util.GlUtil;
import java.io.IOException; import java.io.IOException;
import java.util.Locale; import java.util.Locale;
@ -50,7 +49,7 @@ import javax.microedition.khronos.opengles.GL10;
private final Bitmap logoBitmap; private final Bitmap logoBitmap;
private final Canvas overlayCanvas; private final Canvas overlayCanvas;
@Nullable private GlUtil.Program program; private int program;
@Nullable private GlUtil.Attribute[] attributes; @Nullable private GlUtil.Attribute[] attributes;
@Nullable private GlUtil.Uniform[] uniforms; @Nullable private GlUtil.Uniform[] uniforms;
@ -78,40 +77,27 @@ import javax.microedition.khronos.opengles.GL10;
@Override @Override
public void initialize() { public void initialize() {
String vertexShaderCode;
String fragmentShaderCode;
try { try {
program = vertexShaderCode = GlUtil.loadAsset(context, "bitmap_overlay_video_processor_vertex.glsl");
new GlUtil.Program( fragmentShaderCode =
context, GlUtil.loadAsset(context, "bitmap_overlay_video_processor_fragment.glsl");
/* vertexShaderFilePath= */ "bitmap_overlay_video_processor_vertex.glsl",
/* fragmentShaderFilePath= */ "bitmap_overlay_video_processor_fragment.glsl");
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
program.use(); program = GlUtil.compileProgram(vertexShaderCode, fragmentShaderCode);
GlUtil.Attribute[] attributes = program.getAttributes(); GlUtil.Attribute[] attributes = GlUtil.getAttributes(program);
GlUtil.Uniform[] uniforms = GlUtil.getUniforms(program);
for (GlUtil.Attribute attribute : attributes) { for (GlUtil.Attribute attribute : attributes) {
if (attribute.name.equals("a_position")) { if (attribute.name.equals("a_position")) {
attribute.setBuffer( attribute.setBuffer(new float[] {-1, -1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, 1, 1, 0, 1}, 4);
new float[] {
-1, -1, 0, 1,
1, -1, 0, 1,
-1, 1, 0, 1,
1, 1, 0, 1
},
4);
} else if (attribute.name.equals("a_texcoord")) { } else if (attribute.name.equals("a_texcoord")) {
attribute.setBuffer( attribute.setBuffer(new float[] {0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1}, 4);
new float[] {
0, 0, 0, 1,
1, 0, 0, 1,
0, 1, 0, 1,
1, 1, 0, 1
},
4);
} }
} }
this.attributes = attributes; this.attributes = attributes;
this.uniforms = checkNotNull(program).getUniforms(); this.uniforms = uniforms;
GLES20.glGenTextures(1, textures, 0); GLES20.glGenTextures(1, textures, 0);
GLES20.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); GLES20.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); GLES20.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
@ -140,8 +126,9 @@ import javax.microedition.khronos.opengles.GL10;
GlUtil.checkGlError(); GlUtil.checkGlError();
// Run the shader program. // Run the shader program.
GlUtil.Uniform[] uniforms = checkNotNull(this.uniforms); GlUtil.Uniform[] uniforms = Assertions.checkNotNull(this.uniforms);
GlUtil.Attribute[] attributes = checkNotNull(this.attributes); GlUtil.Attribute[] attributes = Assertions.checkNotNull(this.attributes);
GLES20.glUseProgram(program);
for (GlUtil.Uniform uniform : uniforms) { for (GlUtil.Uniform uniform : uniforms) {
switch (uniform.name) { switch (uniform.name) {
case "tex_sampler_0": case "tex_sampler_0":

View File

@ -54,160 +54,6 @@ public final class GlUtil {
/** Thrown when the required EGL version is not supported by the device. */ /** Thrown when the required EGL version is not supported by the device. */
public static final class UnsupportedEglVersionException extends Exception {} public static final class UnsupportedEglVersionException extends Exception {}
/** GL program. */
public static final class Program {
/** The identifier of a compiled and linked GLSL shader program. */
private final int programId;
/**
* Compiles a GL shader program from vertex and fragment shader code.
*
* @param vertexShaderCode GLES20 vertex shader program.
* @param fragmentShaderCode GLES20 fragment shader program.
*/
public Program(String vertexShaderCode, String fragmentShaderCode) {
programId = GLES20.glCreateProgram();
checkGlError();
// Add the vertex and fragment shaders.
addShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
addShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
// Link and check for errors.
GLES20.glLinkProgram(programId);
int[] linkStatus = new int[] {GLES20.GL_FALSE};
GLES20.glGetProgramiv(programId, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
throwGlException(
"Unable to link shader program: \n" + GLES20.glGetProgramInfoLog(programId));
}
checkGlError();
}
/**
* Compiles a GL shader program from vertex and fragment shader code.
*
* @param context The {@link Context}.
* @param vertexShaderFilePath The path to a GLES20 vertex shader program.
* @param fragmentShaderFilePath The path to a fragment shader program.
* @throws IOException When failing to read the shader files.
*/
public Program(Context context, String vertexShaderFilePath, String fragmentShaderFilePath)
throws IOException {
this(loadAsset(context, vertexShaderFilePath), loadAsset(context, fragmentShaderFilePath));
}
/**
* Compiles a GL shader program from vertex and fragment shader code.
*
* @param vertexShaderCode GLES20 vertex shader program as arrays of strings. Strings are joined
* by adding a new line character in between each of them.
* @param fragmentShaderCode GLES20 fragment shader program as arrays of strings. Strings are
* joined by adding a new line character in between each of them.
*/
public Program(String[] vertexShaderCode, String[] fragmentShaderCode) {
this(TextUtils.join("\n", vertexShaderCode), TextUtils.join("\n", fragmentShaderCode));
}
/** Uses the program. */
public void use() {
GLES20.glUseProgram(programId);
}
/** Deletes the program. Deleted programs cannot be used again. */
public void delete() {
GLES20.glDeleteProgram(programId);
}
/** Returns the location of an {@link Attribute}. */
public int glGetAttribLocation(String attributeName) {
return GLES20.glGetAttribLocation(programId, attributeName);
}
/** Returns the location of a {@link Uniform}. */
public int glGetUniformLocation(String uniformName) {
return GLES20.glGetUniformLocation(programId, uniformName);
}
/** Returns the program's {@link Attribute}s. */
public Attribute[] getAttributes() {
int[] attributeCount = new int[1];
GLES20.glGetProgramiv(programId, GLES20.GL_ACTIVE_ATTRIBUTES, attributeCount, 0);
if (attributeCount[0] != 2) {
throw new IllegalStateException("Expected two attributes.");
}
Attribute[] attributes = new Attribute[attributeCount[0]];
for (int i = 0; i < attributeCount[0]; i++) {
attributes[i] = createAttribute(i);
}
return attributes;
}
/** Returns the program's {@link Uniform}s. */
public Uniform[] getUniforms() {
int[] uniformCount = new int[1];
GLES20.glGetProgramiv(programId, GLES20.GL_ACTIVE_UNIFORMS, uniformCount, 0);
Uniform[] uniforms = new Uniform[uniformCount[0]];
for (int i = 0; i < uniformCount[0]; i++) {
uniforms[i] = createUniform(i);
}
return uniforms;
}
private Uniform createUniform(int index) {
int[] length = new int[1];
GLES20.glGetProgramiv(programId, GLES20.GL_ACTIVE_UNIFORM_MAX_LENGTH, length, 0);
int[] type = new int[1];
int[] size = new int[1];
byte[] name = new byte[length[0]];
int[] ignore = new int[1];
GLES20.glGetActiveUniform(programId, index, length[0], ignore, 0, size, 0, type, 0, name, 0);
String nameString = new String(name, 0, strlen(name));
int location = glGetAttribLocation(nameString);
int typeInt = type[0];
return new Uniform(nameString, location, typeInt);
}
private Attribute createAttribute(int index) {
int[] length = new int[1];
GLES20.glGetProgramiv(programId, GLES20.GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, length, 0);
int[] type = new int[1];
int[] size = new int[1];
byte[] nameBytes = new byte[length[0]];
int[] ignore = new int[1];
GLES20.glGetActiveAttrib(
programId, index, length[0], ignore, 0, size, 0, type, 0, nameBytes, 0);
String name = new String(nameBytes, 0, strlen(nameBytes));
int location = glGetAttribLocation(name);
return new Attribute(name, index, location);
}
private void addShader(int type, String shaderCode) {
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
int[] result = new int[] {GLES20.GL_FALSE};
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, result, 0);
if (result[0] != GLES20.GL_TRUE) {
throwGlException(GLES20.glGetShaderInfoLog(shader) + ", source: " + shaderCode);
}
GLES20.glAttachShader(programId, shader);
GLES20.glDeleteShader(shader);
checkGlError();
}
}
/** /**
* GL attribute, which can be attached to a buffer with {@link Attribute#setBuffer(float[], int)}. * GL attribute, which can be attached to a buffer with {@link Attribute#setBuffer(float[], int)}.
*/ */
@ -222,11 +68,26 @@ public final class GlUtil {
@Nullable private Buffer buffer; @Nullable private Buffer buffer;
private int size; private int size;
/** Creates a new GL attribute. */ /**
public Attribute(String name, int index, int location) { * Creates a new GL attribute.
this.name = name; *
* @param program The identifier of a compiled and linked GLSL shader program.
* @param index The index of the attribute. After this instance has been constructed, the name
* of the attribute is available via the {@link #name} field.
*/
public Attribute(int program, int index) {
int[] len = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, len, 0);
int[] type = new int[1];
int[] size = new int[1];
byte[] nameBytes = new byte[len[0]];
int[] ignore = new int[1];
GLES20.glGetActiveAttrib(program, index, len[0], ignore, 0, size, 0, type, 0, nameBytes, 0);
name = new String(nameBytes, 0, strlen(nameBytes));
location = GLES20.glGetAttribLocation(program, name);
this.index = index; this.index = index;
this.location = location;
} }
/** /**
@ -276,12 +137,28 @@ public final class GlUtil {
private int texId; private int texId;
private int unit; private int unit;
/** Creates a new GL uniform. */ /**
public Uniform(String name, int location, int type) { * Creates a new GL uniform.
this.name = name; *
this.location = location; * @param program The identifier of a compiled and linked GLSL shader program.
this.type = type; * @param index The index of the uniform. After this instance has been constructed, the name of
this.value = new float[16]; * the uniform is available via the {@link #name} field.
*/
public Uniform(int program, int index) {
int[] len = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_ACTIVE_UNIFORM_MAX_LENGTH, len, 0);
int[] type = new int[1];
int[] size = new int[1];
byte[] name = new byte[len[0]];
int[] ignore = new int[1];
GLES20.glGetActiveUniform(program, index, len[0], ignore, 0, size, 0, type, 0, name, 0);
this.name = new String(name, 0, strlen(name));
location = GLES20.glGetUniformLocation(program, this.name);
this.type = type[0];
value = new float[16];
} }
/** /**
@ -455,6 +332,74 @@ public final class GlUtil {
Api17.focusSurface(eglDisplay, eglContext, surface, width, height); Api17.focusSurface(eglDisplay, eglContext, surface, width, height);
} }
/**
* Builds a GL shader program from vertex and fragment shader code.
*
* @param vertexCode GLES20 vertex shader program as arrays of strings. Strings are joined by
* adding a new line character in between each of them.
* @param fragmentCode GLES20 fragment shader program as arrays of strings. Strings are joined by
* adding a new line character in between each of them.
* @return GLES20 program id.
*/
public static int compileProgram(String[] vertexCode, String[] fragmentCode) {
return compileProgram(TextUtils.join("\n", vertexCode), TextUtils.join("\n", fragmentCode));
}
/**
* Builds a GL shader program from vertex and fragment shader code.
*
* @param vertexCode GLES20 vertex shader program.
* @param fragmentCode GLES20 fragment shader program.
* @return GLES20 program id.
*/
public static int compileProgram(String vertexCode, String fragmentCode) {
int program = GLES20.glCreateProgram();
checkGlError();
// Add the vertex and fragment shaders.
addShader(GLES20.GL_VERTEX_SHADER, vertexCode, program);
addShader(GLES20.GL_FRAGMENT_SHADER, fragmentCode, program);
// Link and check for errors.
GLES20.glLinkProgram(program);
int[] linkStatus = new int[] {GLES20.GL_FALSE};
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
throwGlException("Unable to link shader program: \n" + GLES20.glGetProgramInfoLog(program));
}
checkGlError();
return program;
}
/** Returns the {@link Attribute}s in the specified {@code program}. */
public static Attribute[] getAttributes(int program) {
int[] attributeCount = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_ACTIVE_ATTRIBUTES, attributeCount, 0);
if (attributeCount[0] != 2) {
throw new IllegalStateException("Expected two attributes.");
}
Attribute[] attributes = new Attribute[attributeCount[0]];
for (int i = 0; i < attributeCount[0]; i++) {
attributes[i] = new Attribute(program, i);
}
return attributes;
}
/** Returns the {@link Uniform}s in the specified {@code program}. */
public static Uniform[] getUniforms(int program) {
int[] uniformCount = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_ACTIVE_UNIFORMS, uniformCount, 0);
Uniform[] uniforms = new Uniform[uniformCount[0]];
for (int i = 0; i < uniformCount[0]; i++) {
uniforms[i] = new Uniform(program, i);
}
return uniforms;
}
/** /**
* Deletes a GL texture. * Deletes a GL texture.
* *
@ -533,6 +478,22 @@ public final class GlUtil {
return texId[0]; return texId[0];
} }
private static void addShader(int type, String source, int program) {
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
int[] result = new int[] {GLES20.GL_FALSE};
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, result, 0);
if (result[0] != GLES20.GL_TRUE) {
throwGlException(GLES20.glGetShaderInfoLog(shader) + ", source: " + source);
}
GLES20.glAttachShader(program, shader);
GLES20.glDeleteShader(shader);
checkGlError();
}
private static void throwGlException(String errorMsg) { private static void throwGlException(String errorMsg) {
Log.e(TAG, errorMsg); Log.e(TAG, errorMsg);
if (glAssertionsEnabled) { if (glAssertionsEnabled) {

View File

@ -15,8 +15,6 @@
*/ */
package com.google.android.exoplayer2.video; package com.google.android.exoplayer2.video;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import android.content.Context; import android.content.Context;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView;
@ -142,7 +140,7 @@ public final class VideoDecoderGLSurfaceView extends GLSurfaceView
// glDrawArrays uses it. // glDrawArrays uses it.
private final FloatBuffer[] textureCoords; private final FloatBuffer[] textureCoords;
@Nullable private GlUtil.Program program; private int program;
private int colorMatrixLocation; private int colorMatrixLocation;
// Accessed only from the GL thread. // Accessed only from the GL thread.
@ -163,9 +161,9 @@ public final class VideoDecoderGLSurfaceView extends GLSurfaceView
@Override @Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) { public void onSurfaceCreated(GL10 unused, EGLConfig config) {
program = new GlUtil.Program(VERTEX_SHADER, FRAGMENT_SHADER); program = GlUtil.compileProgram(VERTEX_SHADER, FRAGMENT_SHADER);
program.use(); GLES20.glUseProgram(program);
int posLocation = program.glGetAttribLocation("in_pos"); int posLocation = GLES20.glGetAttribLocation(program, "in_pos");
GLES20.glEnableVertexAttribArray(posLocation); GLES20.glEnableVertexAttribArray(posLocation);
GLES20.glVertexAttribPointer( GLES20.glVertexAttribPointer(
posLocation, posLocation,
@ -174,14 +172,14 @@ public final class VideoDecoderGLSurfaceView extends GLSurfaceView
/* normalized= */ false, /* normalized= */ false,
/* stride= */ 0, /* stride= */ 0,
TEXTURE_VERTICES); TEXTURE_VERTICES);
texLocations[0] = checkNotNull(program).glGetAttribLocation("in_tc_y"); texLocations[0] = GLES20.glGetAttribLocation(program, "in_tc_y");
GLES20.glEnableVertexAttribArray(texLocations[0]); GLES20.glEnableVertexAttribArray(texLocations[0]);
texLocations[1] = checkNotNull(program).glGetAttribLocation("in_tc_u"); texLocations[1] = GLES20.glGetAttribLocation(program, "in_tc_u");
GLES20.glEnableVertexAttribArray(texLocations[1]); GLES20.glEnableVertexAttribArray(texLocations[1]);
texLocations[2] = checkNotNull(program).glGetAttribLocation("in_tc_v"); texLocations[2] = GLES20.glGetAttribLocation(program, "in_tc_v");
GLES20.glEnableVertexAttribArray(texLocations[2]); GLES20.glEnableVertexAttribArray(texLocations[2]);
GlUtil.checkGlError(); GlUtil.checkGlError();
colorMatrixLocation = checkNotNull(program).glGetUniformLocation("mColorConversion"); colorMatrixLocation = GLES20.glGetUniformLocation(program, "mColorConversion");
GlUtil.checkGlError(); GlUtil.checkGlError();
setupTextures(); setupTextures();
GlUtil.checkGlError(); GlUtil.checkGlError();
@ -298,7 +296,7 @@ public final class VideoDecoderGLSurfaceView extends GLSurfaceView
private void setupTextures() { private void setupTextures() {
GLES20.glGenTextures(3, yuvTextures, /* offset= */ 0); GLES20.glGenTextures(3, yuvTextures, /* offset= */ 0);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
GLES20.glUniform1i(checkNotNull(program).glGetUniformLocation(TEXTURE_UNIFORMS[i]), i); GLES20.glUniform1i(GLES20.glGetUniformLocation(program, TEXTURE_UNIFORMS[i]), i);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yuvTextures[i]); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yuvTextures[i]);
GLES20.glTexParameterf( GLES20.glTexParameterf(

View File

@ -15,7 +15,6 @@
*/ */
package com.google.android.exoplayer2.video.spherical; package com.google.android.exoplayer2.video.spherical;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.GlUtil.checkGlError; import static com.google.android.exoplayer2.util.GlUtil.checkGlError;
import android.opengl.GLES11Ext; import android.opengl.GLES11Ext;
@ -91,12 +90,11 @@ import java.nio.FloatBuffer;
}; };
private int stereoMode; private int stereoMode;
@Nullable private GlUtil.Program program;
@Nullable private MeshData leftMeshData; @Nullable private MeshData leftMeshData;
@Nullable private MeshData rightMeshData; @Nullable private MeshData rightMeshData;
// Program related GL items. These are only valid if program != 0. // Program related GL items. These are only valid if program != 0.
private int program;
private int mvpMatrixHandle; private int mvpMatrixHandle;
private int uTexMatrixHandle; private int uTexMatrixHandle;
private int positionHandle; private int positionHandle;
@ -121,12 +119,12 @@ import java.nio.FloatBuffer;
/** Initializes of the GL components. */ /** Initializes of the GL components. */
/* package */ void init() { /* package */ void init() {
program = new GlUtil.Program(VERTEX_SHADER_CODE, FRAGMENT_SHADER_CODE); program = GlUtil.compileProgram(VERTEX_SHADER_CODE, FRAGMENT_SHADER_CODE);
mvpMatrixHandle = program.glGetUniformLocation("uMvpMatrix"); mvpMatrixHandle = GLES20.glGetUniformLocation(program, "uMvpMatrix");
uTexMatrixHandle = program.glGetUniformLocation("uTexMatrix"); uTexMatrixHandle = GLES20.glGetUniformLocation(program, "uTexMatrix");
positionHandle = program.glGetAttribLocation("aPosition"); positionHandle = GLES20.glGetAttribLocation(program, "aPosition");
texCoordsHandle = program.glGetAttribLocation("aTexCoords"); texCoordsHandle = GLES20.glGetAttribLocation(program, "aTexCoords");
textureHandle = program.glGetUniformLocation("uTexture"); textureHandle = GLES20.glGetUniformLocation(program, "uTexture");
} }
/** /**
@ -145,7 +143,7 @@ import java.nio.FloatBuffer;
} }
// Configure shader. // Configure shader.
checkNotNull(program).use(); GLES20.glUseProgram(program);
checkGlError(); checkGlError();
GLES20.glEnableVertexAttribArray(positionHandle); GLES20.glEnableVertexAttribArray(positionHandle);
@ -198,9 +196,8 @@ import java.nio.FloatBuffer;
/** Cleans up the GL resources. */ /** Cleans up the GL resources. */
/* package */ void shutdown() { /* package */ void shutdown() {
if (program != null) { if (program != 0) {
program.delete(); GLES20.glDeleteProgram(program);
program = null;
} }
} }

View File

@ -186,7 +186,6 @@ import java.nio.ByteBuffer;
} }
eglSurface = eglSurface =
GlUtil.getEglSurface(eglDisplay, checkNotNull(checkNotNull(encoder).getInputSurface())); GlUtil.getEglSurface(eglDisplay, checkNotNull(checkNotNull(encoder).getInputSurface()));
GlUtil.focusSurface( GlUtil.focusSurface(
eglDisplay, eglDisplay,
eglContext, eglContext,
@ -194,20 +193,17 @@ import java.nio.ByteBuffer;
encoderConfigurationOutputFormat.width, encoderConfigurationOutputFormat.width,
encoderConfigurationOutputFormat.height); encoderConfigurationOutputFormat.height);
decoderTextureId = GlUtil.createExternalTexture(); decoderTextureId = GlUtil.createExternalTexture();
String vertexShaderCode;
GlUtil.Program copyProgram; String fragmentShaderCode;
try { try {
copyProgram = vertexShaderCode = GlUtil.loadAsset(context, "shaders/blit_vertex_shader.glsl");
new GlUtil.Program( fragmentShaderCode = GlUtil.loadAsset(context, "shaders/copy_external_fragment_shader.glsl");
context,
/* vertexShaderFilePath= */ "shaders/blit_vertex_shader.glsl",
/* fragmentShaderFilePath= */ "shaders/copy_external_fragment_shader.glsl");
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
int copyProgram = GlUtil.compileProgram(vertexShaderCode, fragmentShaderCode);
copyProgram.use(); GLES20.glUseProgram(copyProgram);
GlUtil.Attribute[] copyAttributes = copyProgram.getAttributes(); GlUtil.Attribute[] copyAttributes = GlUtil.getAttributes(copyProgram);
checkState(copyAttributes.length == 2, "Expected program to have two vertex attributes."); checkState(copyAttributes.length == 2, "Expected program to have two vertex attributes.");
for (GlUtil.Attribute copyAttribute : copyAttributes) { for (GlUtil.Attribute copyAttribute : copyAttributes) {
if (copyAttribute.name.equals("a_position")) { if (copyAttribute.name.equals("a_position")) {
@ -233,7 +229,7 @@ import java.nio.ByteBuffer;
} }
copyAttribute.bind(); copyAttribute.bind();
} }
GlUtil.Uniform[] copyUniforms = copyProgram.getUniforms(); GlUtil.Uniform[] copyUniforms = GlUtil.getUniforms(copyProgram);
checkState(copyUniforms.length == 2, "Expected program to have two uniforms."); checkState(copyUniforms.length == 2, "Expected program to have two uniforms.");
for (GlUtil.Uniform copyUniform : copyUniforms) { for (GlUtil.Uniform copyUniform : copyUniforms) {
if (copyUniform.name.equals("tex_sampler")) { if (copyUniform.name.equals("tex_sampler")) {