OLD | NEW |
| (Empty) |
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.GLES11Ext; | |
14 import android.opengl.GLES20; | |
15 | |
16 import org.webrtc.GlShader; | |
17 import org.webrtc.GlUtil; | |
18 | |
19 import java.nio.ByteBuffer; | |
20 import java.nio.FloatBuffer; | |
21 import java.util.Arrays; | |
22 import java.util.IdentityHashMap; | |
23 import java.util.Map; | |
24 | |
25 /** | |
26 * Helper class to draw an opaque quad on the target viewport location. Rotation
, mirror, and | |
27 * cropping is specified using a 4x4 texture coordinate transform matrix. The fr
ame input can either | |
28 * be an OES texture or YUV textures in I420 format. The GL state must be preser
ved between draw | |
29 * calls, this is intentional to maximize performance. The function release() mu
st be called | |
30 * manually to free the resources held by this object. | |
31 */ | |
32 public class GlRectDrawer implements RendererCommon.GlDrawer { | |
33 // Simple vertex shader, used for both YUV and OES. | |
34 private static final String VERTEX_SHADER_STRING = | |
35 "varying vec2 interp_tc;\n" | |
36 + "attribute vec4 in_pos;\n" | |
37 + "attribute vec4 in_tc;\n" | |
38 + "\n" | |
39 + "uniform mat4 texMatrix;\n" | |
40 + "\n" | |
41 + "void main() {\n" | |
42 + " gl_Position = in_pos;\n" | |
43 + " interp_tc = (texMatrix * in_tc).xy;\n" | |
44 + "}\n"; | |
45 | |
46 private static final String YUV_FRAGMENT_SHADER_STRING = | |
47 "precision mediump float;\n" | |
48 + "varying vec2 interp_tc;\n" | |
49 + "\n" | |
50 + "uniform sampler2D y_tex;\n" | |
51 + "uniform sampler2D u_tex;\n" | |
52 + "uniform sampler2D v_tex;\n" | |
53 + "\n" | |
54 + "void main() {\n" | |
55 // CSC according to http://www.fourcc.org/fccyvrgb.php | |
56 + " float y = texture2D(y_tex, interp_tc).r;\n" | |
57 + " float u = texture2D(u_tex, interp_tc).r - 0.5;\n" | |
58 + " float v = texture2D(v_tex, interp_tc).r - 0.5;\n" | |
59 + " gl_FragColor = vec4(y + 1.403 * v, " | |
60 + " y - 0.344 * u - 0.714 * v, " | |
61 + " y + 1.77 * u, 1);\n" | |
62 + "}\n"; | |
63 | |
64 private static final String RGB_FRAGMENT_SHADER_STRING = | |
65 "precision mediump float;\n" | |
66 + "varying vec2 interp_tc;\n" | |
67 + "\n" | |
68 + "uniform sampler2D rgb_tex;\n" | |
69 + "\n" | |
70 + "void main() {\n" | |
71 + " gl_FragColor = texture2D(rgb_tex, interp_tc);\n" | |
72 + "}\n"; | |
73 | |
74 private static final String OES_FRAGMENT_SHADER_STRING = | |
75 "#extension GL_OES_EGL_image_external : require\n" | |
76 + "precision mediump float;\n" | |
77 + "varying vec2 interp_tc;\n" | |
78 + "\n" | |
79 + "uniform samplerExternalOES oes_tex;\n" | |
80 + "\n" | |
81 + "void main() {\n" | |
82 + " gl_FragColor = texture2D(oes_tex, interp_tc);\n" | |
83 + "}\n"; | |
84 | |
85 // Vertex coordinates in Normalized Device Coordinates, i.e. (-1, -1) is botto
m-left and (1, 1) is | |
86 // top-right. | |
87 private static final FloatBuffer FULL_RECTANGLE_BUF = | |
88 GlUtil.createFloatBuffer(new float[] { | |
89 -1.0f, -1.0f, // Bottom left. | |
90 1.0f, -1.0f, // Bottom right. | |
91 -1.0f, 1.0f, // Top left. | |
92 1.0f, 1.0f, // Top right. | |
93 }); | |
94 | |
95 // Texture coordinates - (0, 0) is bottom-left and (1, 1) is top-right. | |
96 private static final FloatBuffer FULL_RECTANGLE_TEX_BUF = | |
97 GlUtil.createFloatBuffer(new float[] { | |
98 0.0f, 0.0f, // Bottom left. | |
99 1.0f, 0.0f, // Bottom right. | |
100 0.0f, 1.0f, // Top left. | |
101 1.0f, 1.0f // Top right. | |
102 }); | |
103 | |
104 private static class Shader { | |
105 public final GlShader glShader; | |
106 public final int texMatrixLocation; | |
107 | |
108 public Shader(String fragmentShader) { | |
109 this.glShader = new GlShader(VERTEX_SHADER_STRING, fragmentShader); | |
110 this.texMatrixLocation = glShader.getUniformLocation("texMatrix"); | |
111 } | |
112 } | |
113 | |
114 // The keys are one of the fragments shaders above. | |
115 private final Map<String, Shader> shaders = new IdentityHashMap<String, Shader
>(); | |
116 | |
117 /** | |
118 * Draw an OES texture frame with specified texture transformation matrix. Req
uired resources are | |
119 * allocated at the first call to this function. | |
120 */ | |
121 @Override | |
122 public void drawOes(int oesTextureId, float[] texMatrix, int frameWidth, int f
rameHeight, | |
123 int viewportX, int viewportY, int viewportWidth, int viewportHeight) { | |
124 prepareShader(OES_FRAGMENT_SHADER_STRING, texMatrix); | |
125 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); | |
126 // updateTexImage() may be called from another thread in another EGL context
, so we need to | |
127 // bind/unbind the texture in each draw call so that GLES understads it's a
new texture. | |
128 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, oesTextureId); | |
129 drawRectangle(viewportX, viewportY, viewportWidth, viewportHeight); | |
130 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); | |
131 } | |
132 | |
133 /** | |
134 * Draw a RGB(A) texture frame with specified texture transformation matrix. R
equired resources | |
135 * are allocated at the first call to this function. | |
136 */ | |
137 @Override | |
138 public void drawRgb(int textureId, float[] texMatrix, int frameWidth, int fram
eHeight, | |
139 int viewportX, int viewportY, int viewportWidth, int viewportHeight) { | |
140 prepareShader(RGB_FRAGMENT_SHADER_STRING, texMatrix); | |
141 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); | |
142 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); | |
143 drawRectangle(viewportX, viewportY, viewportWidth, viewportHeight); | |
144 // Unbind the texture as a precaution. | |
145 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); | |
146 } | |
147 | |
148 /** | |
149 * Draw a YUV frame with specified texture transformation matrix. Required res
ources are | |
150 * allocated at the first call to this function. | |
151 */ | |
152 @Override | |
153 public void drawYuv(int[] yuvTextures, float[] texMatrix, int frameWidth, int
frameHeight, | |
154 int viewportX, int viewportY, int viewportWidth, int viewportHeight) { | |
155 prepareShader(YUV_FRAGMENT_SHADER_STRING, texMatrix); | |
156 // Bind the textures. | |
157 for (int i = 0; i < 3; ++i) { | |
158 GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); | |
159 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yuvTextures[i]); | |
160 } | |
161 drawRectangle(viewportX, viewportY, viewportWidth, viewportHeight); | |
162 // Unbind the textures as a precaution.. | |
163 for (int i = 0; i < 3; ++i) { | |
164 GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); | |
165 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); | |
166 } | |
167 } | |
168 | |
169 private void drawRectangle(int x, int y, int width, int height) { | |
170 // Draw quad. | |
171 GLES20.glViewport(x, y, width, height); | |
172 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); | |
173 } | |
174 | |
175 private void prepareShader(String fragmentShader, float[] texMatrix) { | |
176 final Shader shader; | |
177 if (shaders.containsKey(fragmentShader)) { | |
178 shader = shaders.get(fragmentShader); | |
179 } else { | |
180 // Lazy allocation. | |
181 shader = new Shader(fragmentShader); | |
182 shaders.put(fragmentShader, shader); | |
183 shader.glShader.useProgram(); | |
184 // Initialize fragment shader uniform values. | |
185 if (fragmentShader == YUV_FRAGMENT_SHADER_STRING) { | |
186 GLES20.glUniform1i(shader.glShader.getUniformLocation("y_tex"), 0); | |
187 GLES20.glUniform1i(shader.glShader.getUniformLocation("u_tex"), 1); | |
188 GLES20.glUniform1i(shader.glShader.getUniformLocation("v_tex"), 2); | |
189 } else if (fragmentShader == RGB_FRAGMENT_SHADER_STRING) { | |
190 GLES20.glUniform1i(shader.glShader.getUniformLocation("rgb_tex"), 0); | |
191 } else if (fragmentShader == OES_FRAGMENT_SHADER_STRING) { | |
192 GLES20.glUniform1i(shader.glShader.getUniformLocation("oes_tex"), 0); | |
193 } else { | |
194 throw new IllegalStateException("Unknown fragment shader: " + fragmentSh
ader); | |
195 } | |
196 GlUtil.checkNoGLES2Error("Initialize fragment shader uniform values."); | |
197 // Initialize vertex shader attributes. | |
198 shader.glShader.setVertexAttribArray("in_pos", 2, FULL_RECTANGLE_BUF); | |
199 shader.glShader.setVertexAttribArray("in_tc", 2, FULL_RECTANGLE_TEX_BUF); | |
200 } | |
201 shader.glShader.useProgram(); | |
202 // Copy the texture transformation matrix over. | |
203 GLES20.glUniformMatrix4fv(shader.texMatrixLocation, 1, false, texMatrix, 0); | |
204 } | |
205 | |
206 /** | |
207 * Release all GLES resources. This needs to be done manually, otherwise the r
esources are leaked. | |
208 */ | |
209 @Override | |
210 public void release() { | |
211 for (Shader shader : shaders.values()) { | |
212 shader.glShader.release(); | |
213 } | |
214 shaders.clear(); | |
215 } | |
216 } | |
OLD | NEW |