1 /* 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 package org.webrtc; 12 13 import android.opengl.GLES20; 14 15 import java.nio.FloatBuffer; 16 17 // Helper class for handling OpenGL shaders and shader programs. 18 public class GlShader { 19 private static final String TAG = "GlShader"; 20 compileShader(int shaderType, String source)21 private static int compileShader(int shaderType, String source) { 22 final int shader = GLES20.glCreateShader(shaderType); 23 if (shader == 0) { 24 throw new RuntimeException("glCreateShader() failed. GLES20 error: " + GLES20.glGetError()); 25 } 26 GLES20.glShaderSource(shader, source); 27 GLES20.glCompileShader(shader); 28 int[] compileStatus = new int[] {GLES20.GL_FALSE}; 29 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 30 if (compileStatus[0] != GLES20.GL_TRUE) { 31 Logging.e( 32 TAG, "Compile error " + GLES20.glGetShaderInfoLog(shader) + " in shader:\n" + source); 33 throw new RuntimeException(GLES20.glGetShaderInfoLog(shader)); 34 } 35 GlUtil.checkNoGLES2Error("compileShader"); 36 return shader; 37 } 38 39 private int program; 40 GlShader(String vertexSource, String fragmentSource)41 public GlShader(String vertexSource, String fragmentSource) { 42 final int vertexShader = compileShader(GLES20.GL_VERTEX_SHADER, vertexSource); 43 final int fragmentShader = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); 44 program = GLES20.glCreateProgram(); 45 if (program == 0) { 46 throw new RuntimeException("glCreateProgram() failed. GLES20 error: " + GLES20.glGetError()); 47 } 48 GLES20.glAttachShader(program, vertexShader); 49 GLES20.glAttachShader(program, fragmentShader); 50 GLES20.glLinkProgram(program); 51 int[] linkStatus = new int[] {GLES20.GL_FALSE}; 52 GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); 53 if (linkStatus[0] != GLES20.GL_TRUE) { 54 Logging.e(TAG, "Could not link program: " + GLES20.glGetProgramInfoLog(program)); 55 throw new RuntimeException(GLES20.glGetProgramInfoLog(program)); 56 } 57 // According to the documentation of glLinkProgram(): 58 // "After the link operation, applications are free to modify attached shader objects, compile 59 // attached shader objects, detach shader objects, delete shader objects, and attach additional 60 // shader objects. None of these operations affects the information log or the program that is 61 // part of the program object." 62 // But in practice, detaching shaders from the program seems to break some devices. Deleting the 63 // shaders are fine however - it will delete them when they are no longer attached to a program. 64 GLES20.glDeleteShader(vertexShader); 65 GLES20.glDeleteShader(fragmentShader); 66 GlUtil.checkNoGLES2Error("Creating GlShader"); 67 } 68 getAttribLocation(String label)69 public int getAttribLocation(String label) { 70 if (program == -1) { 71 throw new RuntimeException("The program has been released"); 72 } 73 int location = GLES20.glGetAttribLocation(program, label); 74 if (location < 0) { 75 throw new RuntimeException("Could not locate '" + label + "' in program"); 76 } 77 return location; 78 } 79 80 /** 81 * Enable and upload a vertex array for attribute `label`. The vertex data is specified in 82 * `buffer` with `dimension` number of components per vertex. 83 */ setVertexAttribArray(String label, int dimension, FloatBuffer buffer)84 public void setVertexAttribArray(String label, int dimension, FloatBuffer buffer) { 85 setVertexAttribArray(label, dimension, 0 /* stride */, buffer); 86 } 87 88 /** 89 * Enable and upload a vertex array for attribute `label`. The vertex data is specified in 90 * `buffer` with `dimension` number of components per vertex and specified `stride`. 91 */ setVertexAttribArray(String label, int dimension, int stride, FloatBuffer buffer)92 public void setVertexAttribArray(String label, int dimension, int stride, FloatBuffer buffer) { 93 if (program == -1) { 94 throw new RuntimeException("The program has been released"); 95 } 96 int location = getAttribLocation(label); 97 GLES20.glEnableVertexAttribArray(location); 98 GLES20.glVertexAttribPointer(location, dimension, GLES20.GL_FLOAT, false, stride, buffer); 99 GlUtil.checkNoGLES2Error("setVertexAttribArray"); 100 } 101 getUniformLocation(String label)102 public int getUniformLocation(String label) { 103 if (program == -1) { 104 throw new RuntimeException("The program has been released"); 105 } 106 int location = GLES20.glGetUniformLocation(program, label); 107 if (location < 0) { 108 throw new RuntimeException("Could not locate uniform '" + label + "' in program"); 109 } 110 return location; 111 } 112 useProgram()113 public void useProgram() { 114 if (program == -1) { 115 throw new RuntimeException("The program has been released"); 116 } 117 synchronized (EglBase.lock) { 118 GLES20.glUseProgram(program); 119 } 120 GlUtil.checkNoGLES2Error("glUseProgram"); 121 } 122 release()123 public void release() { 124 Logging.d(TAG, "Deleting shader."); 125 // Delete program, automatically detaching any shaders from it. 126 if (program != -1) { 127 GLES20.glDeleteProgram(program); 128 program = -1; 129 } 130 } 131 } 132