1 /*
2 * Copyright 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "ScreenRecord"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include "Program.h"
22
23 #include <GLES2/gl2.h>
24 #include <GLES2/gl2ext.h>
25
26 #include <assert.h>
27
28 using namespace android;
29
30 // 4x4 identity matrix
31 const float Program::kIdentity[] = {
32 1.0f, 0.0f, 0.0f, 0.0f,
33 0.0f, 1.0f, 0.0f, 0.0f,
34 0.0f, 0.0f, 1.0f, 0.0f,
35 0.0f, 0.0f, 0.0f, 1.0f
36 };
37
38 // Simple vertex shader. Texture coord calc includes matrix for GLConsumer
39 // transform.
40 static const char* kVertexShader =
41 "uniform mat4 uMVPMatrix;\n"
42 "uniform mat4 uGLCMatrix;\n"
43 "attribute vec4 aPosition;\n"
44 "attribute vec4 aTextureCoord;\n"
45 "varying vec2 vTextureCoord;\n"
46 "void main() {\n"
47 " gl_Position = uMVPMatrix * aPosition;\n"
48 " vTextureCoord = (uGLCMatrix * aTextureCoord).xy;\n"
49 "}\n";
50
51 // Trivial fragment shader for external texture.
52 static const char* kExtFragmentShader =
53 "#extension GL_OES_EGL_image_external : require\n"
54 "precision mediump float;\n"
55 "varying vec2 vTextureCoord;\n"
56 "uniform samplerExternalOES uTexture;\n"
57 "void main() {\n"
58 " gl_FragColor = texture2D(uTexture, vTextureCoord);\n"
59 "}\n";
60
61 // Trivial fragment shader for mundane texture.
62 static const char* kFragmentShader =
63 "precision mediump float;\n"
64 "varying vec2 vTextureCoord;\n"
65 "uniform sampler2D uTexture;\n"
66 "void main() {\n"
67 " gl_FragColor = texture2D(uTexture, vTextureCoord);\n"
68 //" gl_FragColor = vec4(0.2, 1.0, 0.2, 1.0);\n"
69 "}\n";
70
setup(ProgramType type)71 status_t Program::setup(ProgramType type) {
72 ALOGV("Program::setup type=%d", type);
73 status_t err;
74
75 mProgramType = type;
76
77 GLuint program;
78 if (type == PROGRAM_TEXTURE_2D) {
79 err = createProgram(&program, kVertexShader, kFragmentShader);
80 } else {
81 err = createProgram(&program, kVertexShader, kExtFragmentShader);
82 }
83 if (err != NO_ERROR) {
84 return err;
85 }
86 assert(program != 0);
87
88 maPositionLoc = glGetAttribLocation(program, "aPosition");
89 maTextureCoordLoc = glGetAttribLocation(program, "aTextureCoord");
90 muMVPMatrixLoc = glGetUniformLocation(program, "uMVPMatrix");
91 muGLCMatrixLoc = glGetUniformLocation(program, "uGLCMatrix");
92 muTextureLoc = glGetUniformLocation(program, "uTexture");
93 if ((maPositionLoc | maTextureCoordLoc | muMVPMatrixLoc |
94 muGLCMatrixLoc | muTextureLoc) == -1) {
95 ALOGE("Attrib/uniform lookup failed: %#x", glGetError());
96 glDeleteProgram(program);
97 return UNKNOWN_ERROR;
98 }
99
100 mProgram = program;
101 return NO_ERROR;
102 }
103
release()104 void Program::release() {
105 ALOGV("Program::release");
106 if (mProgram != 0) {
107 glDeleteProgram(mProgram);
108 mProgram = 0;
109 }
110 }
111
createProgram(GLuint * outPgm,const char * vertexShader,const char * fragmentShader)112 status_t Program::createProgram(GLuint* outPgm, const char* vertexShader,
113 const char* fragmentShader) {
114 GLuint vs, fs;
115 status_t err;
116
117 err = compileShader(GL_VERTEX_SHADER, vertexShader, &vs);
118 if (err != NO_ERROR) {
119 return err;
120 }
121 err = compileShader(GL_FRAGMENT_SHADER, fragmentShader, &fs);
122 if (err != NO_ERROR) {
123 glDeleteShader(vs);
124 return err;
125 }
126
127 GLuint program;
128 err = linkShaderProgram(vs, fs, &program);
129 glDeleteShader(vs);
130 glDeleteShader(fs);
131 if (err == NO_ERROR) {
132 *outPgm = program;
133 }
134 return err;
135 }
136
compileShader(GLenum shaderType,const char * src,GLuint * outShader)137 status_t Program::compileShader(GLenum shaderType, const char* src,
138 GLuint* outShader) {
139 GLuint shader = glCreateShader(shaderType);
140 if (shader == 0) {
141 ALOGE("glCreateShader error: %#x", glGetError());
142 return UNKNOWN_ERROR;
143 }
144
145 glShaderSource(shader, 1, &src, NULL);
146 glCompileShader(shader);
147
148 GLint compiled = 0;
149 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
150 if (!compiled) {
151 ALOGE("Compile of shader type %d failed", shaderType);
152 GLint infoLen = 0;
153 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
154 if (infoLen) {
155 char* buf = new char[infoLen];
156 if (buf) {
157 glGetShaderInfoLog(shader, infoLen, NULL, buf);
158 ALOGE("Compile log: %s", buf);
159 delete[] buf;
160 }
161 }
162 glDeleteShader(shader);
163 return UNKNOWN_ERROR;
164 }
165 *outShader = shader;
166 return NO_ERROR;
167 }
168
linkShaderProgram(GLuint vs,GLuint fs,GLuint * outPgm)169 status_t Program::linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) {
170 GLuint program = glCreateProgram();
171 if (program == 0) {
172 ALOGE("glCreateProgram error: %#x", glGetError());
173 return UNKNOWN_ERROR;
174 }
175
176 glAttachShader(program, vs);
177 glAttachShader(program, fs);
178 glLinkProgram(program);
179 GLint linkStatus = GL_FALSE;
180 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
181 if (linkStatus != GL_TRUE) {
182 ALOGE("glLinkProgram failed");
183 GLint bufLength = 0;
184 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
185 if (bufLength) {
186 char* buf = new char[bufLength];
187 if (buf) {
188 glGetProgramInfoLog(program, bufLength, NULL, buf);
189 ALOGE("Link log: %s", buf);
190 delete[] buf;
191 }
192 }
193 glDeleteProgram(program);
194 return UNKNOWN_ERROR;
195 }
196
197 *outPgm = program;
198 return NO_ERROR;
199 }
200
201
202
blit(GLuint texName,const float * texMatrix,int32_t x,int32_t y,int32_t w,int32_t h,bool invert) const203 status_t Program::blit(GLuint texName, const float* texMatrix,
204 int32_t x, int32_t y, int32_t w, int32_t h, bool invert) const {
205 ALOGV("Program::blit %d xy=%d,%d wh=%d,%d", texName, x, y, w, h);
206
207 const float pos[] = {
208 float(x), float(y+h),
209 float(x+w), float(y+h),
210 float(x), float(y),
211 float(x+w), float(y),
212 };
213 const float uv[] = {
214 0.0f, 0.0f,
215 1.0f, 0.0f,
216 0.0f, 1.0f,
217 1.0f, 1.0f,
218 };
219 status_t err;
220
221 err = beforeDraw(texName, texMatrix, pos, uv, invert);
222 if (err == NO_ERROR) {
223 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
224 err = afterDraw();
225 }
226 return err;
227 }
228
drawTriangles(GLuint texName,const float * texMatrix,const float * vertices,const float * texes,size_t count) const229 status_t Program::drawTriangles(GLuint texName, const float* texMatrix,
230 const float* vertices, const float* texes, size_t count) const {
231 ALOGV("Program::drawTriangles texName=%d", texName);
232
233 status_t err;
234
235 err = beforeDraw(texName, texMatrix, vertices, texes, false);
236 if (err == NO_ERROR) {
237 glDrawArrays(GL_TRIANGLES, 0, count);
238 err = afterDraw();
239 }
240 return err;
241 }
242
beforeDraw(GLuint texName,const float * texMatrix,const float * vertices,const float * texes,bool invert) const243 status_t Program::beforeDraw(GLuint texName, const float* texMatrix,
244 const float* vertices, const float* texes, bool invert) const {
245 // Create an orthographic projection matrix based on viewport size.
246 GLint vp[4];
247 glGetIntegerv(GL_VIEWPORT, vp);
248 float screenToNdc[16] = {
249 2.0f/float(vp[2]), 0.0f, 0.0f, 0.0f,
250 0.0f, -2.0f/float(vp[3]), 0.0f, 0.0f,
251 0.0f, 0.0f, 1.0f, 0.0f,
252 -1.0f, 1.0f, 0.0f, 1.0f,
253 };
254 if (invert) {
255 screenToNdc[5] = -screenToNdc[5];
256 screenToNdc[13] = -screenToNdc[13];
257 }
258
259 glUseProgram(mProgram);
260
261 glVertexAttribPointer(maPositionLoc, 2, GL_FLOAT, GL_FALSE, 0, vertices);
262 glVertexAttribPointer(maTextureCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, texes);
263 glEnableVertexAttribArray(maPositionLoc);
264 glEnableVertexAttribArray(maTextureCoordLoc);
265
266 glUniformMatrix4fv(muMVPMatrixLoc, 1, GL_FALSE, screenToNdc);
267 glUniformMatrix4fv(muGLCMatrixLoc, 1, GL_FALSE, texMatrix);
268
269 glActiveTexture(GL_TEXTURE0);
270
271 switch (mProgramType) {
272 case PROGRAM_EXTERNAL_TEXTURE:
273 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texName);
274 break;
275 case PROGRAM_TEXTURE_2D:
276 glBindTexture(GL_TEXTURE_2D, texName);
277 break;
278 default:
279 ALOGE("unexpected program type %d", mProgramType);
280 return UNKNOWN_ERROR;
281 }
282
283 glUniform1i(muTextureLoc, 0);
284
285 GLenum glErr;
286 if ((glErr = glGetError()) != GL_NO_ERROR) {
287 ALOGE("GL error before draw: %#x", glErr);
288 glDisableVertexAttribArray(maPositionLoc);
289 glDisableVertexAttribArray(maTextureCoordLoc);
290 return UNKNOWN_ERROR;
291 }
292
293 return NO_ERROR;
294 }
295
afterDraw() const296 status_t Program::afterDraw() const {
297 glDisableVertexAttribArray(maPositionLoc);
298 glDisableVertexAttribArray(maTextureCoordLoc);
299
300 GLenum glErr;
301 if ((glErr = glGetError()) != GL_NO_ERROR) {
302 ALOGE("GL error after draw: %#x", glErr);
303 return UNKNOWN_ERROR;
304 }
305
306 return NO_ERROR;
307 }
308