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 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 104 void Program::release() { 105 ALOGV("Program::release"); 106 if (mProgram != 0) { 107 glDeleteProgram(mProgram); 108 mProgram = 0; 109 } 110 } 111 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 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 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 203 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 229 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 243 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 296 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