15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/tools/player_x11/gl_video_renderer.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/Xutil.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/buffers.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/video_frame.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/yuv_convert.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gl/gl_surface.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum { kNumYUVPlanes = 3 };
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static GLXContext InitGLContext(Display* display, Window window) {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some versions of NVIDIA's GL libGL.so include a broken version of
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // load it, and use glew to dynamically resolve symbols.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See http://code.google.com/p/chromium/issues/detail?id=16800
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!gfx::GLSurface::InitializeOneOff()) {
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GLSurface::InitializeOneOff failed";
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XWindowAttributes attributes;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XGetWindowAttributes(display, window, &attributes);
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XVisualInfo visual_info_template;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int visual_info_count = 0;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XVisualInfo* visual_info_list = XGetVisualInfo(display, VisualIDMask,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &visual_info_template,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &visual_info_count);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GLXContext context = NULL;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < visual_info_count && !context; ++i) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context = glXCreateContext(display, visual_info_list + i, 0,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               True /* Direct rendering */);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(visual_info_list);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!context) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!glXMakeCurrent(display, window, context)) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glXDestroyContext(display, context);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return context;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Matrix used for the YUV to RGB conversion.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const float kYUV2RGB[9] = {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  1.f, 0.f, 1.403f,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  1.f, -.344f, -.714f,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  1.f, 1.772f, 0.f,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Vertices for a full screen quad.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const float kVertices[8] = {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  -1.f, 1.f,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  -1.f, -1.f,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  1.f, 1.f,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  1.f, -1.f,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Pass-through vertex shader.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kVertexShader[] =
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "varying vec2 interp_tc;\n"
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "\n"
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "attribute vec4 in_pos;\n"
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "attribute vec2 in_tc;\n"
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "\n"
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "void main() {\n"
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "  interp_tc = in_tc;\n"
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "  gl_Position = in_pos;\n"
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "}\n";
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// YUV to RGB pixel shader. Loads a pixel from each plane and pass through the
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// matrix.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kFragmentShader[] =
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "varying vec2 interp_tc;\n"
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "\n"
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "uniform sampler2D y_tex;\n"
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "uniform sampler2D u_tex;\n"
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "uniform sampler2D v_tex;\n"
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "uniform mat3 yuv2rgb;\n"
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "\n"
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "void main() {\n"
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "  float y = texture2D(y_tex, interp_tc).x;\n"
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "  float u = texture2D(u_tex, interp_tc).r - .5;\n"
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "  float v = texture2D(v_tex, interp_tc).r - .5;\n"
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "  vec3 rgb = yuv2rgb * vec3(y, u, v);\n"
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "  gl_FragColor = vec4(rgb, 1);\n"
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "}\n";
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Buffer size for compile errors.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const unsigned int kErrorSize = 4096;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GlVideoRenderer::GlVideoRenderer(Display* display, Window window)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : display_(display),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_(window),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gl_context_(NULL) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GlVideoRenderer::~GlVideoRenderer() {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glXMakeCurrent(display_, 0, NULL);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glXDestroyContext(display_, gl_context_);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid GlVideoRenderer::Paint(
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const scoped_refptr<media::VideoFrame>& video_frame) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gl_context_)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Initialize(video_frame->coded_size(), video_frame->visible_rect());
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Convert YUV frame to RGB.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(video_frame->format() == media::VideoFrame::YV12 ||
121c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         video_frame->format() == media::VideoFrame::I420 ||
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         video_frame->format() == media::VideoFrame::YV16);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(video_frame->stride(media::VideoFrame::kUPlane) ==
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         video_frame->stride(media::VideoFrame::kVPlane));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (glXGetCurrentContext() != gl_context_ ||
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      glXGetCurrentDrawable() != window_) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glXMakeCurrent(display_, window_, gl_context_);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned int i = 0; i < kNumYUVPlanes; ++i) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int width = video_frame->stride(i);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int height = video_frame->rows(i);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glActiveTexture(GL_TEXTURE0 + i);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glPixelStorei(GL_UNPACK_ROW_LENGTH, video_frame->stride(i));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 GL_LUMINANCE, GL_UNSIGNED_BYTE, video_frame->data(i));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glXSwapBuffers(display_, window_);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GlVideoRenderer::Initialize(gfx::Size coded_size, gfx::Rect visible_rect) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!gl_context_);
145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  VLOG(0) << "Initializing GL Renderer...";
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Resize the window to fit that of the video.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XResizeWindow(display_, window_, visible_rect.width(), visible_rect.height());
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gl_context_ = InitGLContext(display_, window_);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(gl_context_) << "Failed to initialize GL context";
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create 3 textures, one for each plane, and bind them to different
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // texture units.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glGenTextures(3, textures_);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glActiveTexture(GL_TEXTURE0);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glBindTexture(GL_TEXTURE_2D, textures_[0]);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glEnable(GL_TEXTURE_2D);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glActiveTexture(GL_TEXTURE1);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glBindTexture(GL_TEXTURE_2D, textures_[1]);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glEnable(GL_TEXTURE_2D);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glActiveTexture(GL_TEXTURE2);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glBindTexture(GL_TEXTURE_2D, textures_[2]);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glEnable(GL_TEXTURE_2D);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GLuint program = glCreateProgram();
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create our YUV->RGB shader.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* vs_source = kVertexShader;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int vs_size = sizeof(kVertexShader);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glShaderSource(vertex_shader, 1, &vs_source, &vs_size);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glCompileShader(vertex_shader);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GL_FALSE;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &result);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char log[kErrorSize];
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int len = 0;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glGetShaderInfoLog(vertex_shader, kErrorSize - 1, &len, log);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    log[kErrorSize - 1] = 0;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(FATAL) << log;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glAttachShader(program, vertex_shader);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glDeleteShader(vertex_shader);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* ps_source = kFragmentShader;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ps_size = sizeof(kFragmentShader);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glShaderSource(fragment_shader, 1, &ps_source, &ps_size);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glCompileShader(fragment_shader);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = GL_FALSE;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &result);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char log[kErrorSize];
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int len = 0;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glGetShaderInfoLog(fragment_shader, kErrorSize - 1, &len, log);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    log[kErrorSize - 1] = 0;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(FATAL) << log;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glAttachShader(program, fragment_shader);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glDeleteShader(fragment_shader);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glLinkProgram(program);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = GL_FALSE;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glGetProgramiv(program, GL_LINK_STATUS, &result);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char log[kErrorSize];
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int len = 0;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glGetProgramInfoLog(program, kErrorSize - 1, &len, log);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    log[kErrorSize - 1] = 0;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(FATAL) << log;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glUseProgram(program);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glDeleteProgram(program);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Bind parameters.
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glUniform1i(glGetUniformLocation(program, "y_tex"), 0);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glUniform1i(glGetUniformLocation(program, "u_tex"), 1);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glUniform1i(glGetUniformLocation(program, "v_tex"), 2);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int yuv2rgb_location = glGetUniformLocation(program, "yuv2rgb");
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glUniformMatrix3fv(yuv2rgb_location, 1, GL_TRUE, kYUV2RGB);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pos_location = glGetAttribLocation(program, "in_pos");
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glEnableVertexAttribArray(pos_location);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tc_location = glGetAttribLocation(program, "in_tc");
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glEnableVertexAttribArray(tc_location);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float verts[8];
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float x0 = static_cast<float>(visible_rect.x()) / coded_size.width();
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float y0 = static_cast<float>(visible_rect.y()) / coded_size.height();
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float x1 = static_cast<float>(visible_rect.right()) / coded_size.width();
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float y1 = static_cast<float>(visible_rect.bottom()) / coded_size.height();
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  verts[0] = x0; verts[1] = y0;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  verts[2] = x0; verts[3] = y1;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  verts[4] = x1; verts[5] = y0;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  verts[6] = x1; verts[7] = y1;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, verts);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We are getting called on a thread. Release the context so that it can be
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // made current on the main thread.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glXMakeCurrent(display_, 0, NULL);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
252