title: Use OpenGL ES2.0 to render video on GLSurfaceView, but the texture is gray
body: <p>I am using OpenGLES to render videos. The decoded YUV420 video frame are mapped as textures to a GLSurfaceView. The YUV420 frame is correctly decoded. Everytime there is an available frame, drawFrame() will be called and the frame is supposed to be rendered. Howerver, the video frame did not show up at all, and the texture is gray all the time. My opengl code is here:</p>
  
  <pre><code>    static const char VERTEX_SHADER[] =
              "varying vec2 interp_tc;\n"
                      "attribute vec4 in_pos;\n"
                      "attribute vec2 in_tc;\n"
                      "void main() {\n"
                      "  gl_Position = in_pos;\n"
                      "  interp_tc = in_tc;\n"
                      "}\n";
  
      static const char FRAGMENT_SHADER[] =
              "precision mediump float;\n"
                      "varying vec2 interp_tc;\n"
                      "uniform sampler2D y_tex;\n"
                      "uniform sampler2D u_tex;\n"
                      "uniform sampler2D v_tex;\n"
                      "void main() {\n"
                      "  float y = 1.164 * (texture2D(y_tex, interp_tc).r - 0.0625);\n"
                      "  float u = texture2D(u_tex, interp_tc).r - 0.5;\n"
                      "  float v = texture2D(v_tex, interp_tc).r - 0.5;\n"
                      "  gl_FragColor = vec4(y + 1.596 * v, "
                      "                      y - 0.391 * u - 0.813 * v, "
                      "                      y + 2.018 * u, "
                      "                      1.0);\n"
                      "}\n";
  
  
      const GLfloat TEXTURE_VERTICES[] = {
              -1.0f, 1.0f,
              -1.0f, -1.0f,
              1.0f, 1.0f,
              1.0f, -1.0f,};
  
      const char* TEXTURE_UNIFORMS[] = {"y_tex", "u_tex", "v_tex"};
      GLuint yuvTextures[3];
  
      void addShader(int type, const char* source, int program) {
          int result[1] = {GL_FALSE};
          int shader = glCreateShader(type);
          glShaderSource(shader, 1, &amp;source, NULL);
          glCompileShader(shader);
          GLint compiled = 0;
          glGetShaderiv(shader, GL_COMPILE_STATUS, &amp;compiled);
          glAttachShader(program, shader);
          glDeleteShader(shader);
      }
  
  
      bool GLRenderer::init()
      {
          EGLBoolean returnValue;
          EGLint majorVersion;
          EGLint minorVersion;
          EGLConfig myConfig = {0};
          EGLint numConfig = 0;
          EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
          EGLint s_configAttribs[] = {
                  EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
                  EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
                  EGL_NONE };
          const EGLint RGBA8888ConfigAttr[] = {
                  EGL_BUFFER_SIZE,     24,
                  EGL_BLUE_SIZE,       8,
                  EGL_GREEN_SIZE,      8,
                  EGL_RED_SIZE,        8,
                  EGL_DEPTH_SIZE,      0,
                  EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,
                  EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
                  EGL_NONE
          };
  
          dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
          checkEglError("eglGetDisplay");
          if (dpy == EGL_NO_DISPLAY) {
              LOGI("eglGetDisplay returned EGL_NO_DISPLAY.\n");
              return false;
          }
  
          returnValue = eglInitialize(dpy, &amp;majorVersion, &amp;minorVersion);
          checkEglError("eglInitialize", returnValue);
          if (returnValue != EGL_TRUE) {
              LOGI("eglInitialize failed\n");
              return false;
          }
  
          returnValue = eglChooseConfig(dpy, RGBA8888ConfigAttr, &amp;myConfig, 1, &amp;numConfig);
          checkEglError("eglChooseConfig", returnValue);
          if (returnValue != EGL_TRUE || numConfig != 1) {
              LOGI("eglInitialize failed\n");
              return false;
          }
  
          surface = eglCreateWindowSurface(dpy, myConfig, static_cast&lt;EGLNativeWindowType&gt;(_window), NULL);
          checkEglError("eglCreateWindowSurface");
          if (surface == EGL_NO_SURFACE) {
              if(DEBUG) {
                  memset(tmp,0,sizeof(tmp));
                  sprintf(tmp,"eglCreateWindowSurface error! \n");
                  LogGL(tmp);
              }
              return false;
          }
  
          context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
          checkEglError("eglCreateContext");
          if (context == EGL_NO_CONTEXT) {
              if(DEBUG) {
                  memset(tmp,0,sizeof(tmp));
                  sprintf(tmp,"eglCreateContext error \n");
                  LogGL(tmp);
              }
              return false;
          }
  
          returnValue = eglMakeCurrent(dpy, surface, surface, context);
          checkEglError("eglMakeCurrent", returnValue);
          if (returnValue != EGL_TRUE) {
              return false;
          }
  
          eglQuerySurface(dpy, surface, EGL_WIDTH, &amp;w);
          checkEglError("eglQuerySurface");
          eglQuerySurface(dpy, surface, EGL_HEIGHT, &amp;h);
          checkEglError("eglQuerySurface");
  
          if(!setupGraphics(w, h)) {
              fprintf(stderr, "Could not set up graphics.\n");
              return false;
          }
  
          if(!setupTextures()) {
              fprintf(stderr, "Could not set up Textures.\n");
              return false;
          }
  
          eglSwapInterval(dpy,0);
  
          return true;
      }
  
  
      bool GLRenderer::setupGraphics(int w, int h) {
          gProgram = glCreateProgram();
          if (!gProgram) {
              return false;
          }
          addShader(GL_VERTEX_SHADER, VERTEX_SHADER, gProgram);
          addShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER, gProgram);
  
          glLinkProgram(gProgram);
          GLint linkStatus = GL_FALSE;
          glGetProgramiv(gProgram, GL_LINK_STATUS, &amp;linkStatus);
          if (linkStatus != GL_TRUE) {
              if(DEBUG) {
                  memset(tmp,0,sizeof(tmp));
                  sprintf(tmp,"glGetProgramiv error \n");
                  LogGL(tmp);
              }
          }
          glUseProgram(gProgram);
          gvPositionHandle = glGetAttribLocation(gProgram, "in_pos");
          glEnableVertexAttribArray(gvPositionHandle);
          glVertexAttribPointer(
                  gvPositionHandle, 2, GL_FLOAT, false, 0, TEXTURE_VERTICES);
          gYuvTexSamplerHandle = glGetAttribLocation(gProgram, "in_tc");
          glEnableVertexAttribArray(gYuvTexSamplerHandle);
  
          glViewport(0, 0, w, h);
          checkGlError("glViewport");
  
          return true;
      }
  
      bool GLRenderer::setupTextures() {
          glGenTextures(3, yuvTextures);
          for (int i = 0; i &lt; 3; i++)  {
              glActiveTexture(GL_TEXTURE0 + i);
              glUniform1i(glGetUniformLocation(gProgram, TEXTURE_UNIFORMS[i]), i);
              glBindTexture(GL_TEXTURE_2D, yuvTextures[i]);
              glTexParameterf(GL_TEXTURE_2D,
                              GL_TEXTURE_MIN_FILTER, GL_LINEAR);
              glTexParameterf(GL_TEXTURE_2D,
                              GL_TEXTURE_MAG_FILTER, GL_LINEAR);
              glTexParameterf(GL_TEXTURE_2D,
                              GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
              glTexParameterf(GL_TEXTURE_2D,
                              GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
          }
          //checkNoGLES2Error();
          return true;
      }
  
      void GLRenderer::drawFrame(int YStride, int UVStride, int iWidth, int iHeight, const char* YData, const char* UData, const char* VData) {
          glUseProgram(gProgram);
          glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
          glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
          glDisable(GL_DEPTH_TEST);
          glUseProgram(gProgram);
  
          int yuvStrides[3];
          yuvStrides[0] = YStride;
          yuvStrides[1] = UVStride;
          yuvStrides[2] = UVStride;
  
          float crop = (float) iWidth / yuvStrides[0];
          GLfloat textureCoords[] = {
                  0.0f, 0.0f,
                  0.0f, 1.0f,
                  crop, 0.0f,
                  crop, 1.0f,};
  
          glVertexAttribPointer(
                  gYuvTexSamplerHandle, 2, GL_FLOAT, false, 0, textureCoords);
          glVertexAttribPointer(
                  gvPositionHandle, 2, GL_FLOAT, false, 0, TEXTURE_VERTICES);
          glEnableVertexAttribArray(gvPositionHandle);
          glEnableVertexAttribArray(gYuvTexSamplerHandle);
  
          eglQuerySurface(dpy, surface, EGL_WIDTH, &amp;w);
          checkEglError("eglQuerySurface");
          eglQuerySurface(dpy, surface, EGL_HEIGHT, &amp;h);
          checkEglError("eglQuerySurface");
          glViewport(0, 0, w, h);
  
          char *yuvPlanes[3];
  
          yuvPlanes[0] = (char *)YData;
          yuvPlanes[1] = (char *)UData;
          yuvPlanes[2] = (char *)VData;
          for (int i = 0; i &lt; 3; i++) {
              int h = (i == 0) ? iHeight : (iHeight + 1) / 2;
              glActiveTexture(GL_TEXTURE0 + i);
              glBindTexture(GL_TEXTURE_2D, yuvTextures[i]);
              glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
              glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, yuvStrides[i],
                           h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yuvPlanes[i]);
          }
  
          glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  
          eglSwapBuffers(dpy, surface);
          checkEglError("eglSwapBuffers");
      }
  </code></pre>