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