1 /* 2 * Copyright (C) 2021 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.systemui.car.wm.activity.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 libcore.io.Streams; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.InputStreamReader; 31 import java.nio.ByteBuffer; 32 import java.nio.ByteOrder; 33 import java.nio.FloatBuffer; 34 import java.nio.IntBuffer; 35 36 /** 37 * A helper class for simple OpenGL operations 38 */ 39 public class GLHelper { 40 41 private static final String TAG = GLHelper.class.getSimpleName(); 42 private static final int SIZEOF_FLOAT = 4; 43 44 /** 45 * Creates an OpenGL program that uses the provided shader sources and returns the id of the 46 * created program 47 * 48 * @param vertexShaderSource The source for the vertex shader 49 * @param fragmentShaderSource The source for the fragment shader 50 * @return The id of the created program 51 */ createProgram(String vertexShaderSource, String fragmentShaderSource)52 public static int createProgram(String vertexShaderSource, String fragmentShaderSource) { 53 int vertexShader = compileShader(GLES30.GL_VERTEX_SHADER, vertexShaderSource); 54 int fragmentShader = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderSource); 55 56 int programId = GLES30.glCreateProgram(); 57 checkGlErrors("glCreateProgram"); 58 59 GLES30.glAttachShader(programId, vertexShader); 60 GLES30.glAttachShader(programId, fragmentShader); 61 62 // glDeleteShader flags these shaders to be deleted, the shaders 63 // are not actually deleted until the program they are attached to are deleted 64 GLES30.glDeleteShader(vertexShader); 65 checkGlErrors("glDeleteShader"); 66 GLES30.glDeleteShader(fragmentShader); 67 checkGlErrors("glDeleteShader"); 68 69 GLES30.glLinkProgram(programId); 70 checkGlErrors("glLinkProgram"); 71 72 return programId; 73 } 74 75 /** 76 * Creates and binds a texture and returns the id of the created texture 77 * 78 * @param textureIdBuffer The IntBuffer that will contain the created texture id 79 * @param textureTarget The texture target for the created texture 80 * @return The id of the created and bound texture 81 */ createAndBindTextureObject(IntBuffer textureIdBuffer, int textureTarget)82 public static int createAndBindTextureObject(IntBuffer textureIdBuffer, int textureTarget) { 83 GLES30.glGenTextures(1, textureIdBuffer); 84 85 int textureId = textureIdBuffer.get(0); 86 87 GLES30.glBindTexture(textureTarget, textureId); 88 checkGlErrors("glBindTexture"); 89 90 // We define the filters that will be applied to the textures if 91 // they get minified or magnified when they are sampled 92 GLES30.glTexParameterf(textureTarget, GLES30.GL_TEXTURE_MIN_FILTER, 93 GLES30.GL_LINEAR); 94 GLES30.glTexParameterf(textureTarget, GLES30.GL_TEXTURE_MAG_FILTER, 95 GLES30.GL_LINEAR); 96 97 // Set the wrap parameters for if the edges of the texture do not fill the surface 98 GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_WRAP_S, 99 GLES30.GL_CLAMP_TO_EDGE); 100 GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_WRAP_T, 101 GLES30.GL_CLAMP_TO_EDGE); 102 103 return textureId; 104 } 105 106 /** 107 * Creates and binds a Framebuffer object 108 * 109 * @param frameBuffer the IntBuffer that will contain the created Framebuffer ID 110 * @return The id of the created and bound Framebuffer 111 */ createAndBindFramebuffer(IntBuffer frameBuffer)112 public static int createAndBindFramebuffer(IntBuffer frameBuffer) { 113 GLES30.glGenFramebuffers(1, frameBuffer); 114 checkGlErrors("glGenFramebuffers"); 115 116 int frameBufferId = frameBuffer.get(0); 117 118 GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, frameBufferId); 119 checkGlErrors("glBindFramebuffer"); 120 121 return frameBufferId; 122 } 123 124 /** 125 * Retrieves a string of an OpenGL shader 126 * 127 * @param id the ID of the raw shader resource 128 * @return The shader script, null if the shader failed to load 129 */ getShaderFromRaw(Context context, int id)130 public static @Nullable String getShaderFromRaw(Context context, int id) { 131 try { 132 InputStream stream = context.getResources().openRawResource(id); 133 return new String(Streams.readFully(new InputStreamReader(stream))); 134 } catch (IOException e) { 135 Slog.e(TAG, "Failed to load shader"); 136 return null; 137 } 138 } 139 140 /** 141 * Creates a FloatBuffer to hold texture and vertex coordinates 142 * 143 * @param coords The coordinates that will be held in the FloatBuffer 144 * @return a FloatBuffer containing the provided coordinates 145 */ createFloatBuffer(float[] coords)146 public static FloatBuffer createFloatBuffer(float[] coords) { 147 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(coords.length * SIZEOF_FLOAT); 148 byteBuffer.order(ByteOrder.nativeOrder()); 149 150 FloatBuffer floatBuffer = byteBuffer.asFloatBuffer(); 151 floatBuffer.put(coords); 152 floatBuffer.position(0); 153 return floatBuffer; 154 } 155 156 /** 157 * @return a float[] representing a 4x4 identity matrix 158 */ getIdentityMatrix()159 public static float[] getIdentityMatrix() { 160 float[] identityMatrix = new float[16]; 161 Matrix.setIdentityM(identityMatrix, 0); 162 return identityMatrix; 163 } 164 165 /** 166 * Checks for GL errors, logging any errors found 167 * 168 * @param func The name of the most recent GL function called 169 * @return a boolean representing if there was a GL error or not 170 */ checkGlErrors(String func)171 public static boolean checkGlErrors(String func) { 172 boolean hadError = false; 173 int error; 174 175 while ((error = GLES30.glGetError()) != GLES30.GL_NO_ERROR) { 176 if (Build.IS_ENG || Build.IS_USERDEBUG) { 177 Slog.e(TAG, func + " failed: error " + error, new Throwable()); 178 } 179 hadError = true; 180 } 181 return hadError; 182 } 183 compileShader(int shaderType, String shaderSource)184 private static int compileShader(int shaderType, String shaderSource) { 185 int shader = GLES30.glCreateShader(shaderType); 186 GLES30.glShaderSource(shader, shaderSource); 187 188 GLES30.glCompileShader(shader); 189 checkGlErrors("glCompileShader"); 190 191 return shader; 192 } 193 } 194