1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.pm.blurredbackground; 18 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.opengl.GLES30; 22 import android.opengl.Matrix; 23 import android.os.Build; 24 import android.util.Slog; 25 26 import com.android.car.CarLog; 27 28 import libcore.io.Streams; 29 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.InputStreamReader; 33 import java.nio.ByteBuffer; 34 import java.nio.ByteOrder; 35 import java.nio.FloatBuffer; 36 import java.nio.IntBuffer; 37 38 /** 39 * A helper class for simple OpenGL operations 40 */ 41 public class GLHelper { 42 43 private static final String TAG = CarLog.tagFor(GLHelper.class); 44 private static final int SIZEOF_FLOAT = 4; 45 46 /** 47 * Creates an OpenGL program that uses the provided shader sources 48 * and returns the id of the created program 49 * 50 * @param vertexShaderSource The source for the vertex shader 51 * @param fragmentShaderSource The source for the fragment shader 52 * @return The id of the created program 53 */ createProgram(String vertexShaderSource, String fragmentShaderSource)54 public static int createProgram(String vertexShaderSource, String fragmentShaderSource) { 55 int vertexShader = compileShader(GLES30.GL_VERTEX_SHADER, vertexShaderSource); 56 int fragmentShader = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderSource); 57 58 int programId = GLES30.glCreateProgram(); 59 checkGlErrors("glCreateProgram"); 60 61 GLES30.glAttachShader(programId, vertexShader); 62 GLES30.glAttachShader(programId, fragmentShader); 63 64 // glDeleteShader flags these shaders to be deleted, the shaders 65 // are not actually deleted until the program they are attached to are deleted 66 GLES30.glDeleteShader(vertexShader); 67 checkGlErrors("glDeleteShader"); 68 GLES30.glDeleteShader(fragmentShader); 69 checkGlErrors("glDeleteShader"); 70 71 GLES30.glLinkProgram(programId); 72 checkGlErrors("glLinkProgram"); 73 74 return programId; 75 } 76 77 /** 78 * Creates and binds a texture and returns the id of the created texture 79 * 80 * @param textureIdBuffer The IntBuffer that will contain the created texture id 81 * @param textureTarget The texture target for the created texture 82 * @return The id of the created and bound texture 83 */ createAndBindTextureObject(IntBuffer textureIdBuffer, int textureTarget)84 public static int createAndBindTextureObject(IntBuffer textureIdBuffer, int textureTarget) { 85 GLES30.glGenTextures(1, textureIdBuffer); 86 87 int textureId = textureIdBuffer.get(0); 88 89 GLES30.glBindTexture(textureTarget, textureId); 90 checkGlErrors("glBindTexture"); 91 92 // We define the filters that will be applied to the textures if 93 // they get minified or magnified when they are sampled 94 GLES30.glTexParameterf(textureTarget, GLES30.GL_TEXTURE_MIN_FILTER, 95 GLES30.GL_LINEAR); 96 GLES30.glTexParameterf(textureTarget, GLES30.GL_TEXTURE_MAG_FILTER, 97 GLES30.GL_LINEAR); 98 99 // Set the wrap parameters for if the edges of the texture do not fill the surface 100 GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_WRAP_S, 101 GLES30.GL_CLAMP_TO_EDGE); 102 GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_WRAP_T, 103 GLES30.GL_CLAMP_TO_EDGE); 104 105 return textureId; 106 } 107 108 /** 109 * Creates and binds a Framebuffer object 110 * 111 * @param frameBuffer the IntBuffer that will contain the created Framebuffer ID 112 * @return The id of the created and bound Framebuffer 113 */ createAndBindFramebuffer(IntBuffer frameBuffer)114 public static int createAndBindFramebuffer(IntBuffer frameBuffer) { 115 GLES30.glGenFramebuffers(1, frameBuffer); 116 checkGlErrors("glGenFramebuffers"); 117 118 int frameBufferId = frameBuffer.get(0); 119 120 GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, frameBufferId); 121 checkGlErrors("glBindFramebuffer"); 122 123 return frameBufferId; 124 } 125 126 /** 127 * Retrieves a string of an OpenGL shader 128 * 129 * @param id the ID of the raw shader resource 130 * @return The shader script, null if the shader failed to load 131 */ getShaderFromRaw(Context context, int id)132 public static @Nullable String getShaderFromRaw(Context context, int id) { 133 try { 134 InputStream stream = context.getResources().openRawResource(id); 135 return new String(Streams.readFully(new InputStreamReader(stream))); 136 } catch (IOException e) { 137 Slog.e(TAG, "Failed to load shader"); 138 return null; 139 } 140 } 141 142 /** 143 * Creates a FloatBuffer to hold texture and vertex coordinates 144 * 145 * @param coords The coordinates that will be held in the FloatBuffer 146 * @return a FloatBuffer containing the provided coordinates 147 */ createFloatBuffer(float[] coords)148 public static FloatBuffer createFloatBuffer(float[] coords) { 149 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(coords.length * SIZEOF_FLOAT); 150 byteBuffer.order(ByteOrder.nativeOrder()); 151 152 FloatBuffer floatBuffer = byteBuffer.asFloatBuffer(); 153 floatBuffer.put(coords); 154 floatBuffer.position(0); 155 return floatBuffer; 156 } 157 158 /** 159 * @return a float[] representing a 4x4 identity matrix 160 */ getIdentityMatrix()161 public static float[] getIdentityMatrix() { 162 float[] identityMatrix = new float[16]; 163 Matrix.setIdentityM(identityMatrix, 0); 164 return identityMatrix; 165 } 166 167 /** 168 * Checks for GL errors, logging any errors found 169 * 170 * @param func The name of the most recent GL function called 171 * @return a boolean representing if there was a GL error or not 172 */ checkGlErrors(String func)173 public static boolean checkGlErrors(String func) { 174 boolean hadError = false; 175 int error; 176 177 while ((error = GLES30.glGetError()) != GLES30.GL_NO_ERROR) { 178 if (Build.IS_ENG || Build.IS_USERDEBUG) { 179 Slog.e(TAG, func + " failed: error " + error, new Throwable()); 180 } 181 hadError = true; 182 } 183 return hadError; 184 } 185 compileShader(int shaderType, String shaderSource)186 private static int compileShader(int shaderType, String shaderSource) { 187 int shader = GLES30.glCreateShader(shaderType); 188 GLES30.glShaderSource(shader, shaderSource); 189 190 GLES30.glCompileShader(shader); 191 checkGlErrors("glCompileShader"); 192 193 return shader; 194 } 195 } 196