1935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org/*
2935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * libjingle
3935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * Copyright 2014, Google Inc.
4935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org *
5935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * Redistribution and use in source and binary forms, with or without
6935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * modification, are permitted provided that the following conditions are met:
7935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org *
8935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
9935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org *     this list of conditions and the following disclaimer.
10935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
11935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org *     this list of conditions and the following disclaimer in the documentation
12935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org *     and/or other materials provided with the distribution.
13935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org *  3. The name of the author may not be used to endorse or promote products
14935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org *     derived from this software without specific prior written permission.
15935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org *
16935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org */
27935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
28935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#if !defined(__has_feature) || !__has_feature(objc_arc)
29935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#error "This file requires ARC support."
30935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#endif
31935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
3252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#import "RTCOpenGLVideoRenderer.h"
33935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
3452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if TARGET_OS_IPHONE
35935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#import <OpenGLES/ES2/gl.h>
3652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#else
3752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#import <OpenGL/gl3.h>
3852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
3952348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org
40935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#import "RTCI420Frame.h"
41935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
42935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// TODO(tkchin): check and log openGL errors. Methods here return BOOLs in
43935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// anticipation of that happening in the future.
44935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
4552348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if TARGET_OS_IPHONE
4652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define RTC_PIXEL_FORMAT GL_LUMINANCE
4752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define SHADER_VERSION
4852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define VERTEX_SHADER_IN "attribute"
4952348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define VERTEX_SHADER_OUT "varying"
5052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define FRAGMENT_SHADER_IN "varying"
5152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define FRAGMENT_SHADER_OUT
5252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define FRAGMENT_SHADER_COLOR "gl_FragColor"
5352348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define FRAGMENT_SHADER_TEXTURE "texture2D"
5452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#else
5552348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define RTC_PIXEL_FORMAT GL_RED
5652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define SHADER_VERSION "#version 150\n"
5752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define VERTEX_SHADER_IN "in"
5852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define VERTEX_SHADER_OUT "out"
5952348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define FRAGMENT_SHADER_IN "in"
6052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define FRAGMENT_SHADER_OUT "out vec4 fragColor;\n"
6152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define FRAGMENT_SHADER_COLOR "fragColor"
6252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#define FRAGMENT_SHADER_TEXTURE "texture"
6352348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
64935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
65935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// Vertex shader doesn't do anything except pass coordinates through.
6652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.orgstatic const char kVertexShaderSource[] =
6752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  SHADER_VERSION
6852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  VERTEX_SHADER_IN " vec2 position;\n"
6952348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  VERTEX_SHADER_IN " vec2 texcoord;\n"
7052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  VERTEX_SHADER_OUT " vec2 v_texcoord;\n"
7152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "void main() {\n"
7252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    gl_Position = vec4(position.x, position.y, 0.0, 1.0);\n"
7352348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    v_texcoord = texcoord;\n"
7452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "}\n";
75935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
76935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// Fragment shader converts YUV values from input textures into a final RGB
77935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// pixel. The conversion formula is from http://www.fourcc.org/fccyvrgb.php.
7852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.orgstatic const char kFragmentShaderSource[] =
7952348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  SHADER_VERSION
8052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "precision highp float;"
8152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  FRAGMENT_SHADER_IN " vec2 v_texcoord;\n"
8252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "uniform lowp sampler2D s_textureY;\n"
8352348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "uniform lowp sampler2D s_textureU;\n"
8452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "uniform lowp sampler2D s_textureV;\n"
8552348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  FRAGMENT_SHADER_OUT
8652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "void main() {\n"
8752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    float y, u, v, r, g, b;\n"
8852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    y = " FRAGMENT_SHADER_TEXTURE "(s_textureY, v_texcoord).r;\n"
8952348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    u = " FRAGMENT_SHADER_TEXTURE "(s_textureU, v_texcoord).r;\n"
9052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    v = " FRAGMENT_SHADER_TEXTURE "(s_textureV, v_texcoord).r;\n"
9152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    u = u - 0.5;\n"
9252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    v = v - 0.5;\n"
9352348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    r = y + 1.403 * v;\n"
9452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    g = y - 0.344 * u - 0.714 * v;\n"
9552348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    b = y + 1.770 * u;\n"
9652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "    " FRAGMENT_SHADER_COLOR " = vec4(r, g, b, 1.0);\n"
9752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  "  }\n";
98935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
99935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// Compiles a shader of the given |type| with GLSL source |source| and returns
100935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// the shader handle or 0 on error.
101935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.orgGLuint CreateShader(GLenum type, const GLchar* source) {
102935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLuint shader = glCreateShader(type);
103935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (!shader) {
104935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return 0;
105935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
106935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glShaderSource(shader, 1, &source, NULL);
107935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glCompileShader(shader);
108935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLint compileStatus = GL_FALSE;
109935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
110935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (compileStatus == GL_FALSE) {
111935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glDeleteShader(shader);
112935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    shader = 0;
113935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
114935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  return shader;
115935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
116935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
117935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// Links a shader program with the given vertex and fragment shaders and
118935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// returns the program handle or 0 on error.
119935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.orgGLuint CreateProgram(GLuint vertexShader, GLuint fragmentShader) {
120935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (vertexShader == 0 || fragmentShader == 0) {
121935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return 0;
122935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
123935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLuint program = glCreateProgram();
124935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (!program) {
125935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return 0;
126935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
127935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glAttachShader(program, vertexShader);
128935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glAttachShader(program, fragmentShader);
129935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glLinkProgram(program);
130935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLint linkStatus = GL_FALSE;
131935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
132935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (linkStatus == GL_FALSE) {
133935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glDeleteProgram(program);
134935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    program = 0;
135935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
136935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  return program;
137935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
138935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
139935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// When modelview and projection matrices are identity (default) the world is
140935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// contained in the square around origin with unit size 2. Drawing to these
141935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// coordinates is equivalent to drawing to the entire screen. The texture is
142935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// stretched over that square using texture coordinates (u, v) that range
143935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// from (0, 0) to (1, 1) inclusive. Texture coordinates are flipped vertically
144935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// here because the incoming frame has origin in upper left hand corner but
145935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// OpenGL expects origin in bottom left corner.
146935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.orgconst GLfloat gVertices[] = {
14752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  // X, Y, U, V.
14852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  -1, -1, 0, 1,  // Bottom left.
14952348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org   1, -1, 1, 1,  // Bottom right.
15052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org   1,  1, 1, 0,  // Top right.
15152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  -1,  1, 0, 0,  // Top left.
152935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org};
153935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
154935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// |kNumTextures| must not exceed 8, which is the limit in OpenGLES2. Two sets
155935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// of 3 textures are used here, one for each of the Y, U and V planes. Having
156935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// two sets alleviates CPU blockage in the event that the GPU is asked to render
157935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// to a texture that is already in use.
158935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.orgstatic const GLsizei kNumTextureSets = 2;
159935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.orgstatic const GLsizei kNumTextures = 3 * kNumTextureSets;
160935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
16152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org@implementation RTCOpenGLVideoRenderer {
16252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if TARGET_OS_IPHONE
163935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  EAGLContext* _context;
16452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#else
16552348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  NSOpenGLContext* _context;
16652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
167935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  BOOL _isInitialized;
168935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  NSUInteger _currentTextureSet;
169935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // Handles for OpenGL constructs.
170935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLuint _textures[kNumTextures];
171935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLuint _program;
17252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if !TARGET_OS_IPHONE
17352348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  GLuint _vertexArray;
17452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
175935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLuint _vertexBuffer;
176935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLint _position;
177935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLint _texcoord;
178935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLint _ySampler;
179935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLint _uSampler;
180935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLint _vSampler;
181935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
182935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
183935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org+ (void)initialize {
184935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // Disable dithering for performance.
185935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glDisable(GL_DITHER);
186935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
187935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
18852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if TARGET_OS_IPHONE
189935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (instancetype)initWithContext:(EAGLContext*)context {
19052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#else
19152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org- (instancetype)initWithContext:(NSOpenGLContext*)context {
19252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
193935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  NSAssert(context != nil, @"context cannot be nil");
194935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (self = [super init]) {
195935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    _context = context;
196935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
197935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  return self;
198935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
199935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
200935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (BOOL)drawFrame:(RTCI420Frame*)frame {
201935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (!_isInitialized) {
202935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return NO;
203935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
204935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (_lastDrawnFrame == frame) {
205935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return NO;
206935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
207935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  [self ensureGLContext];
208935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glClear(GL_COLOR_BUFFER_BIT);
209fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org  if (frame) {
210fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org    if (![self updateTextureSizesForFrame:frame] ||
211fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org        ![self updateTextureDataForFrame:frame]) {
212fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org      return NO;
213fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org    }
21452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if !TARGET_OS_IPHONE
215fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org    glBindVertexArray(_vertexArray);
21652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
217fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
218fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
219fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org  }
22052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if !TARGET_OS_IPHONE
22152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  [_context flushBuffer];
22252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
223935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _lastDrawnFrame = frame;
224935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  return YES;
225935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
226935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
227935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)setupGL {
228935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (_isInitialized) {
229935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return;
230935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
231935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  [self ensureGLContext];
232935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (![self setupProgram]) {
233935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return;
234935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
235935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (![self setupTextures]) {
236935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return;
237935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
238935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (![self setupVertices]) {
239935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return;
240935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
241935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glUseProgram(_program);
242935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
243935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _isInitialized = YES;
244935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
245935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
246935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)teardownGL {
247935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (!_isInitialized) {
248935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return;
249935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
250935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  [self ensureGLContext];
251935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glDeleteProgram(_program);
252935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _program = 0;
253935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glDeleteTextures(kNumTextures, _textures);
254935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glDeleteBuffers(1, &_vertexBuffer);
255935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _vertexBuffer = 0;
25652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if !TARGET_OS_IPHONE
25752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  glDeleteVertexArrays(1, &_vertexArray);
25852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
259935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _isInitialized = NO;
260935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
261935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
262935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#pragma mark - Private
263935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
264935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)ensureGLContext {
26552348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  NSAssert(_context, @"context shouldn't be nil");
26652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if TARGET_OS_IPHONE
267935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if ([EAGLContext currentContext] != _context) {
268935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    [EAGLContext setCurrentContext:_context];
269935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
27052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#else
27152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  if ([NSOpenGLContext currentContext] != _context) {
27252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org    [_context makeCurrentContext];
27352348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  }
27452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
275935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
276935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
277935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (BOOL)setupProgram {
278935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  NSAssert(!_program, @"program already set up");
279935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLuint vertexShader = CreateShader(GL_VERTEX_SHADER, kVertexShaderSource);
28052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  NSAssert(vertexShader, @"failed to create vertex shader");
281935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLuint fragmentShader =
282935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org      CreateShader(GL_FRAGMENT_SHADER, kFragmentShaderSource);
28352348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  NSAssert(fragmentShader, @"failed to create fragment shader");
284935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _program = CreateProgram(vertexShader, fragmentShader);
285935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // Shaders are created only to generate program.
286935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (vertexShader) {
287935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glDeleteShader(vertexShader);
288935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
289935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (fragmentShader) {
290935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glDeleteShader(fragmentShader);
291935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
292935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (!_program) {
293935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return NO;
294935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
295935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _position = glGetAttribLocation(_program, "position");
296935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _texcoord = glGetAttribLocation(_program, "texcoord");
297935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _ySampler = glGetUniformLocation(_program, "s_textureY");
298935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _uSampler = glGetUniformLocation(_program, "s_textureU");
299935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _vSampler = glGetUniformLocation(_program, "s_textureV");
300935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (_position < 0 || _texcoord < 0 || _ySampler < 0 || _uSampler < 0 ||
301935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org      _vSampler < 0) {
302935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return NO;
303935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
304935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  return YES;
305935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
306935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
307935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (BOOL)setupTextures {
308935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glGenTextures(kNumTextures, _textures);
309935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // Set parameters for each of the textures we created.
310935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  for (GLsizei i = 0; i < kNumTextures; i++) {
311935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glActiveTexture(GL_TEXTURE0 + i);
312935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glBindTexture(GL_TEXTURE_2D, _textures[i]);
313935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
314935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
315935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
316935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
317935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
318935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  return YES;
319935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
320935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
321935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (BOOL)updateTextureSizesForFrame:(RTCI420Frame*)frame {
322935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (frame.height == _lastDrawnFrame.height &&
323935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org      frame.width == _lastDrawnFrame.width &&
324935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org      frame.chromaWidth == _lastDrawnFrame.chromaWidth &&
325935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org      frame.chromaHeight == _lastDrawnFrame.chromaHeight) {
326935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return YES;
327935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
328935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLsizei lumaWidth = frame.width;
329935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLsizei lumaHeight = frame.height;
330935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLsizei chromaWidth = frame.chromaWidth;
331935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  GLsizei chromaHeight = frame.chromaHeight;
332935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  for (GLint i = 0; i < kNumTextureSets; i++) {
333935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glActiveTexture(GL_TEXTURE0 + i * 3);
334935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glTexImage2D(GL_TEXTURE_2D,
335935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 0,
33652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org                 RTC_PIXEL_FORMAT,
337935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 lumaWidth,
338935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 lumaHeight,
339935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 0,
34052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org                 RTC_PIXEL_FORMAT,
341935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 GL_UNSIGNED_BYTE,
342935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 0);
343935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glActiveTexture(GL_TEXTURE0 + i * 3 + 1);
344935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glTexImage2D(GL_TEXTURE_2D,
345935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 0,
34652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org                 RTC_PIXEL_FORMAT,
347935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 chromaWidth,
348935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 chromaHeight,
349935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 0,
35052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org                 RTC_PIXEL_FORMAT,
351935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 GL_UNSIGNED_BYTE,
352935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 0);
353935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glActiveTexture(GL_TEXTURE0 + i * 3 + 2);
354935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    glTexImage2D(GL_TEXTURE_2D,
355935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 0,
35652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org                 RTC_PIXEL_FORMAT,
357935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 chromaWidth,
358935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 chromaHeight,
359935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 0,
36052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org                 RTC_PIXEL_FORMAT,
361935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 GL_UNSIGNED_BYTE,
362935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                 0);
363935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
364935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  return YES;
365935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
366935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
367935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (BOOL)updateTextureDataForFrame:(RTCI420Frame*)frame {
368935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  NSUInteger textureOffset = _currentTextureSet * 3;
369935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  NSAssert(textureOffset + 3 <= kNumTextures, @"invalid offset");
370935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  NSParameterAssert(frame.yPitch == frame.width);
371935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  NSParameterAssert(frame.uPitch == frame.chromaWidth);
372935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  NSParameterAssert(frame.vPitch == frame.chromaWidth);
373935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
374935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glActiveTexture(GL_TEXTURE0 + textureOffset);
375935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // When setting texture sampler uniforms, the texture index is used not
376935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // the texture handle.
377935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glUniform1i(_ySampler, textureOffset);
378935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glTexImage2D(GL_TEXTURE_2D,
379935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               0,
38052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org               RTC_PIXEL_FORMAT,
381935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               frame.width,
382935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               frame.height,
383935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               0,
38452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org               RTC_PIXEL_FORMAT,
385935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               GL_UNSIGNED_BYTE,
386935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               frame.yPlane);
387935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
388935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glActiveTexture(GL_TEXTURE0 + textureOffset + 1);
389935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glUniform1i(_uSampler, textureOffset + 1);
390935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glTexImage2D(GL_TEXTURE_2D,
391935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               0,
39252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org               RTC_PIXEL_FORMAT,
393935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               frame.chromaWidth,
394935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               frame.chromaHeight,
395935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               0,
39652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org               RTC_PIXEL_FORMAT,
397935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               GL_UNSIGNED_BYTE,
398935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               frame.uPlane);
399935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
400935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glActiveTexture(GL_TEXTURE0 + textureOffset + 2);
401935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glUniform1i(_vSampler, textureOffset + 2);
402935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glTexImage2D(GL_TEXTURE_2D,
403935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               0,
40452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org               RTC_PIXEL_FORMAT,
405935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               frame.chromaWidth,
406935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               frame.chromaHeight,
407935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               0,
40852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org               RTC_PIXEL_FORMAT,
409935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               GL_UNSIGNED_BYTE,
410935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org               frame.vPlane);
411935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
412935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  _currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
413935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  return YES;
414935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
415935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
416935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (BOOL)setupVertices {
41752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if !TARGET_OS_IPHONE
41852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  NSAssert(!_vertexArray, @"vertex array already set up");
41952348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  glGenVertexArrays(1, &_vertexArray);
42052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  if (!_vertexArray) {
42152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org    return NO;
42252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  }
42352348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org  glBindVertexArray(_vertexArray);
42452348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
425935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  NSAssert(!_vertexBuffer, @"vertex buffer already set up");
426935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glGenBuffers(1, &_vertexBuffer);
427935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  if (!_vertexBuffer) {
42852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#if !TARGET_OS_IPHONE
42952348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org    glDeleteVertexArrays(1, &_vertexArray);
43052348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org    _vertexArray = 0;
43152348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#endif
432935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org    return NO;
433935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  }
434935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
435935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glBufferData(GL_ARRAY_BUFFER, sizeof(gVertices), gVertices, GL_DYNAMIC_DRAW);
436935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
437935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // Read position attribute from |gVertices| with size of 2 and stride of 4
438935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // beginning at the start of the array. The last argument indicates offset
439935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // of data within |gVertices| as supplied to the vertex buffer.
440935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glVertexAttribPointer(
441935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org      _position, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)0);
442935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glEnableVertexAttribArray(_position);
443935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
444935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // Read texcoord attribute from |gVertices| with size of 2 and stride of 4
445935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // beginning at the first texcoord in the array. The last argument indicates
446935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  // offset of data within |gVertices| as supplied to the vertex buffer.
447935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glVertexAttribPointer(_texcoord,
448935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                        2,
449935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                        GL_FLOAT,
450935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                        GL_FALSE,
451935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                        4 * sizeof(GLfloat),
452935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org                        (void*)(2 * sizeof(GLfloat)));
453935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  glEnableVertexAttribArray(_texcoord);
454935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
455935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org  return YES;
456935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org}
457935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org
458935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org@end
459