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