1 /*
2  * libjingle
3  * Copyright 2015 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 package org.webrtc;
29 
30 import android.opengl.GLES20;
31 
32 import org.webrtc.Logging;
33 
34 import java.nio.FloatBuffer;
35 
36 // Helper class for handling OpenGL shaders and shader programs.
37 public class GlShader {
38   private static final String TAG = "GlShader";
39 
compileShader(int shaderType, String source)40   private static int compileShader(int shaderType, String source) {
41     int[] result = new int[] {
42         GLES20.GL_FALSE
43     };
44     int shader = GLES20.glCreateShader(shaderType);
45     GLES20.glShaderSource(shader, source);
46     GLES20.glCompileShader(shader);
47     GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, result, 0);
48     if (result[0] != GLES20.GL_TRUE) {
49       Logging.e(TAG, "Could not compile shader " + shaderType + ":" +
50           GLES20.glGetShaderInfoLog(shader));
51       throw new RuntimeException(GLES20.glGetShaderInfoLog(shader));
52     }
53     GlUtil.checkNoGLES2Error("compileShader");
54     return shader;
55   }
56 
57   private int vertexShader;
58   private int fragmentShader;
59   private int program;
60 
GlShader(String vertexSource, String fragmentSource)61   public GlShader(String vertexSource, String fragmentSource) {
62     vertexShader = compileShader(GLES20.GL_VERTEX_SHADER, vertexSource);
63     fragmentShader = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
64     program = GLES20.glCreateProgram();
65     if (program == 0) {
66       throw new RuntimeException("Could not create program");
67     }
68     GLES20.glAttachShader(program, vertexShader);
69     GLES20.glAttachShader(program, fragmentShader);
70     GLES20.glLinkProgram(program);
71     int[] linkStatus = new int[] {
72       GLES20.GL_FALSE
73     };
74     GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
75     if (linkStatus[0] != GLES20.GL_TRUE) {
76       Logging.e(TAG, "Could not link program: " +
77           GLES20.glGetProgramInfoLog(program));
78       throw new RuntimeException(GLES20.glGetProgramInfoLog(program));
79     }
80     GlUtil.checkNoGLES2Error("Creating GlShader");
81   }
82 
getAttribLocation(String label)83   public int getAttribLocation(String label) {
84     if (program == -1) {
85       throw new RuntimeException("The program has been released");
86     }
87     int location = GLES20.glGetAttribLocation(program, label);
88     if (location < 0) {
89       throw new RuntimeException("Could not locate '" + label + "' in program");
90     }
91     return location;
92   }
93 
94   /**
95    * Enable and upload a vertex array for attribute |label|. The vertex data is specified in
96    * |buffer| with |dimension| number of components per vertex.
97    */
setVertexAttribArray(String label, int dimension, FloatBuffer buffer)98   public void setVertexAttribArray(String label, int dimension, FloatBuffer buffer) {
99     if (program == -1) {
100       throw new RuntimeException("The program has been released");
101     }
102     int location = getAttribLocation(label);
103     GLES20.glEnableVertexAttribArray(location);
104     GLES20.glVertexAttribPointer(location, dimension, GLES20.GL_FLOAT, false, 0, buffer);
105     GlUtil.checkNoGLES2Error("setVertexAttribArray");
106   }
107 
getUniformLocation(String label)108   public int getUniformLocation(String label) {
109     if (program == -1) {
110       throw new RuntimeException("The program has been released");
111     }
112     int location = GLES20.glGetUniformLocation(program, label);
113     if (location < 0) {
114       throw new RuntimeException("Could not locate uniform '" + label + "' in program");
115     }
116     return location;
117   }
118 
useProgram()119   public void useProgram() {
120     if (program == -1) {
121       throw new RuntimeException("The program has been released");
122     }
123     GLES20.glUseProgram(program);
124     GlUtil.checkNoGLES2Error("glUseProgram");
125   }
126 
release()127   public void release() {
128     Logging.d(TAG, "Deleting shader.");
129     // Flag shaders for deletion (does not delete until no longer attached to a program).
130     if (vertexShader != -1) {
131       GLES20.glDeleteShader(vertexShader);
132       vertexShader = -1;
133     }
134     if (fragmentShader != -1) {
135       GLES20.glDeleteShader(fragmentShader);
136       fragmentShader = -1;
137     }
138     // Delete program, automatically detaching any shaders from it.
139     if (program != -1) {
140       GLES20.glDeleteProgram(program);
141       program = -1;
142     }
143   }
144 }
145