• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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