Home | History | Annotate | Download | only in screenrecord
      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