Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 1 | /* |
kjellander | b24317b | 2016-02-10 07:54:43 -0800 | [diff] [blame] | 2 | * Copyright 2015 The WebRTC project authors. All Rights Reserved. |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 3 | * |
kjellander | b24317b | 2016-02-10 07:54:43 -0800 | [diff] [blame] | 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. |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 9 | */ |
| 10 | |
| 11 | package org.webrtc; |
| 12 | |
| 13 | import android.opengl.GLES20; |
Jiayang Liu | 5975b3c | 2015-09-16 13:40:53 -0700 | [diff] [blame] | 14 | |
magjed | 59a677a | 2015-06-24 03:59:37 -0700 | [diff] [blame] | 15 | import java.nio.FloatBuffer; |
| 16 | |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 17 | // Helper class for handling OpenGL shaders and shader programs. |
| 18 | public class GlShader { |
| 19 | private static final String TAG = "GlShader"; |
| 20 | |
| 21 | private static int compileShader(int shaderType, String source) { |
magjed | 347c0bb | 2016-02-18 03:47:44 -0800 | [diff] [blame] | 22 | final int shader = GLES20.glCreateShader(shaderType); |
| 23 | if (shader == 0) { |
| 24 | throw new RuntimeException("glCreateShader() failed. GLES20 error: " + GLES20.glGetError()); |
| 25 | } |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 26 | GLES20.glShaderSource(shader, source); |
| 27 | GLES20.glCompileShader(shader); |
sakal | b6760f9 | 2016-09-29 04:12:44 -0700 | [diff] [blame] | 28 | int[] compileStatus = new int[] {GLES20.GL_FALSE}; |
magjed | 347c0bb | 2016-02-18 03:47:44 -0800 | [diff] [blame] | 29 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); |
| 30 | if (compileStatus[0] != GLES20.GL_TRUE) { |
sakal | b6760f9 | 2016-09-29 04:12:44 -0700 | [diff] [blame] | 31 | Logging.e( |
| 32 | TAG, "Could not compile shader " + shaderType + ":" + GLES20.glGetShaderInfoLog(shader)); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 33 | throw new RuntimeException(GLES20.glGetShaderInfoLog(shader)); |
| 34 | } |
| 35 | GlUtil.checkNoGLES2Error("compileShader"); |
| 36 | return shader; |
| 37 | } |
| 38 | |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 39 | private int program; |
| 40 | |
| 41 | public GlShader(String vertexSource, String fragmentSource) { |
magjed | 347c0bb | 2016-02-18 03:47:44 -0800 | [diff] [blame] | 42 | final int vertexShader = compileShader(GLES20.GL_VERTEX_SHADER, vertexSource); |
| 43 | final int fragmentShader = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 44 | program = GLES20.glCreateProgram(); |
| 45 | if (program == 0) { |
magjed | 347c0bb | 2016-02-18 03:47:44 -0800 | [diff] [blame] | 46 | throw new RuntimeException("glCreateProgram() failed. GLES20 error: " + GLES20.glGetError()); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 47 | } |
| 48 | GLES20.glAttachShader(program, vertexShader); |
| 49 | GLES20.glAttachShader(program, fragmentShader); |
| 50 | GLES20.glLinkProgram(program); |
sakal | b6760f9 | 2016-09-29 04:12:44 -0700 | [diff] [blame] | 51 | int[] linkStatus = new int[] {GLES20.GL_FALSE}; |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 52 | GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); |
| 53 | if (linkStatus[0] != GLES20.GL_TRUE) { |
sakal | b6760f9 | 2016-09-29 04:12:44 -0700 | [diff] [blame] | 54 | Logging.e(TAG, "Could not link program: " + GLES20.glGetProgramInfoLog(program)); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 55 | throw new RuntimeException(GLES20.glGetProgramInfoLog(program)); |
| 56 | } |
magjed | 347c0bb | 2016-02-18 03:47:44 -0800 | [diff] [blame] | 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); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 66 | GlUtil.checkNoGLES2Error("Creating GlShader"); |
| 67 | } |
| 68 | |
| 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 | |
magjed | 59a677a | 2015-06-24 03:59:37 -0700 | [diff] [blame] | 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 | */ |
| 84 | public void setVertexAttribArray(String label, int dimension, FloatBuffer buffer) { |
| 85 | if (program == -1) { |
| 86 | throw new RuntimeException("The program has been released"); |
| 87 | } |
| 88 | int location = getAttribLocation(label); |
| 89 | GLES20.glEnableVertexAttribArray(location); |
| 90 | GLES20.glVertexAttribPointer(location, dimension, GLES20.GL_FLOAT, false, 0, buffer); |
| 91 | GlUtil.checkNoGLES2Error("setVertexAttribArray"); |
| 92 | } |
| 93 | |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 94 | public int getUniformLocation(String label) { |
| 95 | if (program == -1) { |
| 96 | throw new RuntimeException("The program has been released"); |
| 97 | } |
| 98 | int location = GLES20.glGetUniformLocation(program, label); |
| 99 | if (location < 0) { |
| 100 | throw new RuntimeException("Could not locate uniform '" + label + "' in program"); |
| 101 | } |
| 102 | return location; |
| 103 | } |
| 104 | |
| 105 | public void useProgram() { |
| 106 | if (program == -1) { |
| 107 | throw new RuntimeException("The program has been released"); |
| 108 | } |
| 109 | GLES20.glUseProgram(program); |
| 110 | GlUtil.checkNoGLES2Error("glUseProgram"); |
| 111 | } |
| 112 | |
| 113 | public void release() { |
Jiayang Liu | 5975b3c | 2015-09-16 13:40:53 -0700 | [diff] [blame] | 114 | Logging.d(TAG, "Deleting shader."); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 115 | // Delete program, automatically detaching any shaders from it. |
| 116 | if (program != -1) { |
| 117 | GLES20.glDeleteProgram(program); |
| 118 | program = -1; |
| 119 | } |
| 120 | } |
| 121 | } |