Index: talk/app/webrtc/java/android/org/webrtc/GlRectDrawer.java |
diff --git a/talk/app/webrtc/java/android/org/webrtc/GlRectDrawer.java b/talk/app/webrtc/java/android/org/webrtc/GlRectDrawer.java |
index abd0ddf08a2cb96f26b71563bdd017aa101cf416..c14abb021949ae2e26c7383f4b561b4b5c266403 100644 |
--- a/talk/app/webrtc/java/android/org/webrtc/GlRectDrawer.java |
+++ b/talk/app/webrtc/java/android/org/webrtc/GlRectDrawer.java |
@@ -36,6 +36,8 @@ import org.webrtc.GlUtil; |
import java.nio.ByteBuffer; |
import java.nio.FloatBuffer; |
import java.util.Arrays; |
+import java.util.IdentityHashMap; |
+import java.util.Map; |
/** |
* Helper class to draw a quad that covers the entire viewport. Rotation, mirror, and cropping is |
@@ -47,7 +49,7 @@ import java.util.Arrays; |
public class GlRectDrawer { |
// Simple vertex shader, used for both YUV and OES. |
private static final String VERTEX_SHADER_STRING = |
- "varying vec2 interp_tc;\n" |
+ "varying vec2 interp_tc;\n" |
+ "attribute vec4 in_pos;\n" |
+ "attribute vec4 in_tc;\n" |
+ "\n" |
@@ -59,7 +61,7 @@ public class GlRectDrawer { |
+ "}\n"; |
private static final String YUV_FRAGMENT_SHADER_STRING = |
- "precision mediump float;\n" |
+ "precision mediump float;\n" |
+ "varying vec2 interp_tc;\n" |
+ "\n" |
+ "uniform sampler2D y_tex;\n" |
@@ -76,8 +78,18 @@ public class GlRectDrawer { |
+ " y + 1.77 * u, 1);\n" |
+ "}\n"; |
+ private static final String RGB_FRAGMENT_SHADER_STRING = |
+ "precision mediump float;\n" |
+ + "varying vec2 interp_tc;\n" |
+ + "\n" |
+ + "uniform sampler2D rgb_tex;\n" |
+ + "\n" |
+ + "void main() {\n" |
+ + " gl_FragColor = texture2D(rgb_tex, interp_tc);\n" |
+ + "}\n"; |
+ |
private static final String OES_FRAGMENT_SHADER_STRING = |
- "#extension GL_OES_EGL_image_external : require\n" |
+ "#extension GL_OES_EGL_image_external : require\n" |
+ "precision mediump float;\n" |
+ "varying vec2 interp_tc;\n" |
+ "\n" |
@@ -103,38 +115,18 @@ public class GlRectDrawer { |
1.0f, 1.0f // Top right. |
}); |
- private GlShader oesShader; |
- private GlShader yuvShader; |
+ // The keys are one of the fragments shaders above. |
+ private final Map<String, GlShader> shaders = new IdentityHashMap<String, GlShader>(); |
private GlShader currentShader; |
private float[] currentTexMatrix; |
private int texMatrixLocation; |
- private void initGeometry(GlShader shader) { |
- shader.setVertexAttribArray("in_pos", 2, FULL_RECTANGLE_BUF); |
- shader.setVertexAttribArray("in_tc", 2, FULL_RECTANGLE_TEX_BUF); |
- } |
- |
/** |
* Draw an OES texture frame with specified texture transformation matrix. Required resources are |
* allocated at the first call to this function. |
*/ |
public void drawOes(int oesTextureId, float[] texMatrix) { |
- // Lazy allocation. |
- if (oesShader == null) { |
- oesShader = new GlShader(VERTEX_SHADER_STRING, OES_FRAGMENT_SHADER_STRING); |
- oesShader.useProgram(); |
- initGeometry(oesShader); |
- } |
- |
- // Set GLES state to OES. |
- if (currentShader != oesShader) { |
- currentShader = oesShader; |
- oesShader.useProgram(); |
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0); |
- currentTexMatrix = null; |
- texMatrixLocation = oesShader.getUniformLocation("texMatrix"); |
- } |
- |
+ prepareShader(OES_FRAGMENT_SHADER_STRING); |
// updateTexImage() may be called from another thread in another EGL context, so we need to |
// bind/unbind the texture in each draw call so that GLES understads it's a new texture. |
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, oesTextureId); |
@@ -143,39 +135,34 @@ public class GlRectDrawer { |
} |
/** |
+ * Draw a RGB(A) texture frame with specified texture transformation matrix. Required resources |
+ * are allocated at the first call to this function. |
+ */ |
+ public void drawRgb(int textureId, float[] texMatrix) { |
+ prepareShader(RGB_FRAGMENT_SHADER_STRING); |
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); |
+ drawRectangle(texMatrix); |
+ // Unbind the texture as a precaution. |
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); |
+ } |
+ |
+ /** |
* Draw a YUV frame with specified texture transformation matrix. Required resources are |
* allocated at the first call to this function. |
*/ |
public void drawYuv(int width, int height, int[] yuvTextures, float[] texMatrix) { |
- // Lazy allocation. |
- if (yuvShader == null) { |
- yuvShader = new GlShader(VERTEX_SHADER_STRING, YUV_FRAGMENT_SHADER_STRING); |
- yuvShader.useProgram(); |
- |
- // Set texture samplers. |
- GLES20.glUniform1i(yuvShader.getUniformLocation("y_tex"), 0); |
- GLES20.glUniform1i(yuvShader.getUniformLocation("u_tex"), 1); |
- GLES20.glUniform1i(yuvShader.getUniformLocation("v_tex"), 2); |
- GlUtil.checkNoGLES2Error("y/u/v_tex glGetUniformLocation"); |
- |
- initGeometry(yuvShader); |
- } |
- |
- // Set GLES state to YUV. |
- if (currentShader != yuvShader) { |
- currentShader = yuvShader; |
- yuvShader.useProgram(); |
- currentTexMatrix = null; |
- texMatrixLocation = yuvShader.getUniformLocation("texMatrix"); |
- } |
- |
+ prepareShader(YUV_FRAGMENT_SHADER_STRING); |
// Bind the textures. |
for (int i = 0; i < 3; ++i) { |
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); |
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yuvTextures[i]); |
} |
- |
drawRectangle(texMatrix); |
+ // Unbind the textures as a precaution.. |
+ for (int i = 0; i < 3; ++i) { |
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); |
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); |
+ } |
} |
private void drawRectangle(float[] texMatrix) { |
@@ -189,17 +176,48 @@ public class GlRectDrawer { |
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); |
} |
+ private void prepareShader(String fragmentShader) { |
+ // Lazy allocation. |
+ if (!shaders.containsKey(fragmentShader)) { |
+ final GlShader shader = new GlShader(VERTEX_SHADER_STRING, fragmentShader); |
+ shaders.put(fragmentShader, shader); |
+ shader.useProgram(); |
+ // Initialize fragment shader uniform values. |
+ if (fragmentShader == YUV_FRAGMENT_SHADER_STRING) { |
+ GLES20.glUniform1i(shader.getUniformLocation("y_tex"), 0); |
+ GLES20.glUniform1i(shader.getUniformLocation("u_tex"), 1); |
+ GLES20.glUniform1i(shader.getUniformLocation("v_tex"), 2); |
+ } else if (fragmentShader == RGB_FRAGMENT_SHADER_STRING) { |
+ GLES20.glUniform1i(shader.getUniformLocation("rgb_tex"), 0); |
+ } else if (fragmentShader == OES_FRAGMENT_SHADER_STRING) { |
+ GLES20.glUniform1i(shader.getUniformLocation("oes_tex"), 0); |
+ } else { |
+ throw new IllegalStateException("Unknown fragment shader: " + fragmentShader); |
+ } |
+ GlUtil.checkNoGLES2Error("Initialize fragment shader uniform values."); |
+ // Initialize vertex shader attributes. |
+ shader.setVertexAttribArray("in_pos", 2, FULL_RECTANGLE_BUF); |
+ shader.setVertexAttribArray("in_tc", 2, FULL_RECTANGLE_TEX_BUF); |
+ } |
+ |
+ // Update GLES state if shader is not already current. |
+ final GlShader shader = shaders.get(fragmentShader); |
+ if (currentShader != shader) { |
+ currentShader = shader; |
+ shader.useProgram(); |
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0); |
+ currentTexMatrix = null; |
+ texMatrixLocation = shader.getUniformLocation("texMatrix"); |
+ } |
+ } |
+ |
/** |
* Release all GLES resources. This needs to be done manually, otherwise the resources are leaked. |
*/ |
public void release() { |
- if (oesShader != null) { |
- oesShader.release(); |
- oesShader = null; |
- } |
- if (yuvShader != null) { |
- yuvShader.release(); |
- yuvShader = null; |
+ for (GlShader shader : shaders.values()) { |
+ shader.release(); |
} |
+ shaders.clear(); |
} |
} |