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.graphics.Rect; 20 import android.opengl.GLES11Ext; 21 import android.opengl.GLES30; 22 23 import java.nio.FloatBuffer; 24 import java.nio.IntBuffer; 25 26 /** 27 * A class containing the OpenGL programs used to render a blurred texture 28 */ 29 public class BlurTextureProgram { 30 31 private static final float[] FRAME_COORDS = { 32 -1.0f, -1.0f, // 0 bottom left 33 1.0f, -1.0f, // 1 bottom right 34 -1.0f, 1.0f, // 2 top left 35 1.0f, 1.0f, // 3 top right 36 }; 37 private static final float[] TEXTURE_COORDS = { 38 0.0f, 0.0f, // 0 bottom left 39 1.0f, 0.0f, // 1 bottom right 40 0.0f, 1.0f, // 2 top left 41 1.0f, 1.0f // 3 top right 42 }; 43 44 private static final float[] INVERTED_TEXTURE_COORDS = { 45 0.0f, 1.0f, // 0 bottom left 46 1.0f, 1.0f, // 1 bottom right 47 0.0f, 0.0f, // 2 top left 48 1.0f, 0.0f // 3 top right 49 }; 50 51 private static final int SIZEOF_FLOAT = 4; 52 private static final int NUM_COORDS_PER_VERTEX = 2; 53 private static final float BLUR_RADIUS = 40.0f; 54 55 private final String mVertexShader; 56 private final String mHorizontalBlurShader; 57 private final String mVerticalBlurShader; 58 59 private final int mHorizontalBlurProgram; 60 private final int mVerticalBlurProgram; 61 62 private final int mWidth; 63 private final int mHeight; 64 65 private final int mScreenshotTextureId; 66 private final IntBuffer mScreenshotTextureBuffer; 67 private final float[] mTexMatrix; 68 private final FloatBuffer mResolutionBuffer; 69 70 private final FloatBuffer mVertexBuffer = GLHelper.createFloatBuffer(FRAME_COORDS); 71 private final FloatBuffer mTexBuffer = GLHelper.createFloatBuffer(TEXTURE_COORDS); 72 private final FloatBuffer mInvertedTexBuffer = GLHelper.createFloatBuffer( 73 INVERTED_TEXTURE_COORDS); 74 75 // Locations of the uniforms and attributes for the horizontal program 76 private final int mUHorizontalMVPMatrixLoc; 77 private final int mUHorizontalTexMatrixLoc; 78 private final int mUHorizontalResolutionLoc; 79 private final int mUHorizontalRadiusLoc; 80 private final int mAHorizontalPositionLoc; 81 private final int mAHorizontalTextureCoordLoc; 82 83 // Locations of the uniforms and attributes for the vertical program 84 private final int mUVerticalMVPMatrixLoc; 85 private final int mUVerticalTexMatrixLoc; 86 private final int mUVerticalResolutionLoc; 87 private final int mUVerticalRadiusLoc; 88 private final int mAVerticalPositionLoc; 89 private final int mAVerticalTextureCoordLoc; 90 91 private final IntBuffer mFrameBuffer = IntBuffer.allocate(1); 92 private final IntBuffer mFirstPassTextureBuffer = IntBuffer.allocate(1); 93 94 private int mFrameBufferId; 95 private int mFirstPassTextureId; 96 97 /** 98 * Constructor for the BlurTextureProgram 99 * 100 * @param screenshotTextureBuffer IntBuffer 101 * @param texMatrix Float array used to scale the screenshot texture 102 * @param vertexShader String containing the horizontal blur shader 103 * @param horizontalBlurShader String containing the fragment shader for horizontal blur 104 * @param verticalBlurShader String containing the fragment shader for vertical blur 105 * @param windowRect Rect representing the location of the window being covered 106 */ BlurTextureProgram( IntBuffer screenshotTextureBuffer, float[] texMatrix, String vertexShader, String horizontalBlurShader, String verticalBlurShader, Rect windowRect )107 BlurTextureProgram( 108 IntBuffer screenshotTextureBuffer, 109 float[] texMatrix, 110 String vertexShader, 111 String horizontalBlurShader, 112 String verticalBlurShader, 113 Rect windowRect 114 ) { 115 mVertexShader = vertexShader; 116 mHorizontalBlurShader = horizontalBlurShader; 117 mVerticalBlurShader = verticalBlurShader; 118 119 mScreenshotTextureBuffer = screenshotTextureBuffer; 120 mScreenshotTextureId = screenshotTextureBuffer.get(0); 121 mTexMatrix = texMatrix; 122 123 mHorizontalBlurProgram = GLHelper.createProgram(mVertexShader, mHorizontalBlurShader); 124 mVerticalBlurProgram = GLHelper.createProgram(mVertexShader, mVerticalBlurShader); 125 126 mWidth = windowRect.width(); 127 mHeight = windowRect.height(); 128 129 mResolutionBuffer = FloatBuffer.wrap(new float[]{(float) mWidth, (float) mHeight, 1.0f}); 130 131 // Initialize the uniform and attribute locations for the horizontal blur program 132 mUHorizontalMVPMatrixLoc = GLES30.glGetUniformLocation(mHorizontalBlurProgram, 133 "uMVPMatrix"); 134 mUHorizontalTexMatrixLoc = GLES30.glGetUniformLocation(mHorizontalBlurProgram, 135 "uTexMatrix"); 136 mUHorizontalResolutionLoc = GLES30.glGetUniformLocation(mHorizontalBlurProgram, 137 "uResolution"); 138 mUHorizontalRadiusLoc = GLES30.glGetUniformLocation(mHorizontalBlurProgram, "uRadius"); 139 140 mAHorizontalPositionLoc = GLES30.glGetAttribLocation(mHorizontalBlurProgram, "aPosition"); 141 mAHorizontalTextureCoordLoc = GLES30.glGetAttribLocation(mHorizontalBlurProgram, 142 "aTextureCoord"); 143 144 // Initialize the uniform and attribute locations for the vertical blur program 145 mUVerticalMVPMatrixLoc = GLES30.glGetUniformLocation(mVerticalBlurProgram, "uMVPMatrix"); 146 mUVerticalTexMatrixLoc = GLES30.glGetUniformLocation(mVerticalBlurProgram, "uTexMatrix"); 147 mUVerticalResolutionLoc = GLES30.glGetUniformLocation(mVerticalBlurProgram, "uResolution"); 148 mUVerticalRadiusLoc = GLES30.glGetUniformLocation(mVerticalBlurProgram, "uRadius"); 149 150 mAVerticalPositionLoc = GLES30.glGetAttribLocation(mVerticalBlurProgram, "aPosition"); 151 mAVerticalTextureCoordLoc = GLES30.glGetAttribLocation(mVerticalBlurProgram, 152 "aTextureCoord"); 153 } 154 155 /** 156 * Executes all of the rendering logic. Sets up FrameBuffers and programs to complete 157 * two rendering passes on the captured screenshot to produce a blur. 158 */ render()159 public void render() { 160 setupProgram(mHorizontalBlurProgram, mScreenshotTextureId, 161 GLES11Ext.GL_TEXTURE_EXTERNAL_OES); 162 setHorizontalUniformsAndAttributes(); 163 164 // Create the framebuffer that will hold the texture we render to 165 // for the first shader pass 166 mFrameBufferId = GLHelper.createAndBindFramebuffer(mFrameBuffer); 167 168 // Create the empty texture that will store the output of the first shader pass (this'll 169 // be held in the Framebuffer Object) 170 mFirstPassTextureId = GLHelper.createAndBindTextureObject(mFirstPassTextureBuffer, 171 GLES30.GL_TEXTURE_2D); 172 173 setupTextureForFramebuffer(mFirstPassTextureId); 174 assertValidFramebufferStatus(); 175 renderToFramebuffer(mFrameBufferId); 176 177 setupProgram(mVerticalBlurProgram, mFirstPassTextureId, GLES30.GL_TEXTURE_2D); 178 setVerticalUniformsAndAttributes(); 179 180 renderToSurface(); 181 cleanupResources(); 182 } 183 184 /** 185 * Cleans up all OpenGL resources used by programs in this class 186 */ cleanupResources()187 public void cleanupResources() { 188 deleteFramebufferTexture(); 189 deleteFrameBuffer(); 190 deletePrograms(); 191 192 GLES30.glFlush(); 193 } 194 195 /** 196 * Attaches a 2D texture image to the active framebuffer object 197 * 198 * @param textureId The ID of the texture to be attached 199 */ setupTextureForFramebuffer(int textureId)200 private void setupTextureForFramebuffer(int textureId) { 201 GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGB, mWidth, mHeight, 0, 202 GLES30.GL_RGB, GLES30.GL_UNSIGNED_BYTE, null); 203 GLHelper.checkGlErrors("glTexImage2D"); 204 GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, 205 GLES30.GL_TEXTURE_2D, textureId, 0); 206 GLHelper.checkGlErrors("glFramebufferTexture2D"); 207 } 208 209 /** 210 * Deletes the texture stored in the framebuffer 211 */ deleteFramebufferTexture()212 private void deleteFramebufferTexture() { 213 GLES30.glDeleteTextures(mFirstPassTextureBuffer.capacity(), mFirstPassTextureBuffer); 214 GLHelper.checkGlErrors("glDeleteTextures"); 215 } 216 217 /** 218 * Deletes the frame buffers. 219 */ deleteFrameBuffer()220 private void deleteFrameBuffer() { 221 GLES30.glDeleteBuffers(1, mFrameBuffer); 222 GLHelper.checkGlErrors("glDeleteBuffers"); 223 } 224 225 /** 226 * Deletes the GL programs. 227 */ deletePrograms()228 private void deletePrograms() { 229 GLES30.glDeleteProgram(mHorizontalBlurProgram); 230 GLHelper.checkGlErrors("glDeleteProgram"); 231 GLES30.glDeleteProgram(mVerticalBlurProgram); 232 GLHelper.checkGlErrors("glDeleteProgram"); 233 } 234 235 /** 236 * Set all of the Uniform and Attribute variable values for the horizontal blur program 237 */ setHorizontalUniformsAndAttributes()238 private void setHorizontalUniformsAndAttributes() { 239 GLES30.glUniformMatrix4fv(mUHorizontalMVPMatrixLoc, 1, false, GLHelper.getIdentityMatrix(), 240 0); 241 GLES30.glUniformMatrix4fv(mUHorizontalTexMatrixLoc, 1, false, mTexMatrix, 0); 242 GLES30.glUniform3fv(mUHorizontalResolutionLoc, 1, mResolutionBuffer); 243 GLES30.glUniform1f(mUHorizontalRadiusLoc, BLUR_RADIUS); 244 245 GLES30.glEnableVertexAttribArray(mAHorizontalPositionLoc); 246 GLES30.glVertexAttribPointer(mAHorizontalPositionLoc, NUM_COORDS_PER_VERTEX, 247 GLES30.GL_FLOAT, false, NUM_COORDS_PER_VERTEX * SIZEOF_FLOAT, mVertexBuffer); 248 249 GLES30.glEnableVertexAttribArray(mAHorizontalTextureCoordLoc); 250 GLES30.glVertexAttribPointer(mAHorizontalTextureCoordLoc, 2, 251 GLES30.GL_FLOAT, false, 2 * SIZEOF_FLOAT, mTexBuffer); 252 } 253 254 /** 255 * Set all of the Uniform and Attribute variable values for the vertical blur program 256 */ setVerticalUniformsAndAttributes()257 private void setVerticalUniformsAndAttributes() { 258 GLES30.glUniformMatrix4fv(mUVerticalMVPMatrixLoc, 1, false, GLHelper.getIdentityMatrix(), 259 0); 260 GLES30.glUniformMatrix4fv(mUVerticalTexMatrixLoc, 1, false, mTexMatrix, 0); 261 GLES30.glUniform3fv(mUVerticalResolutionLoc, 1, mResolutionBuffer); 262 GLES30.glUniform1f(mUVerticalRadiusLoc, BLUR_RADIUS); 263 264 GLES30.glEnableVertexAttribArray(mAVerticalPositionLoc); 265 GLES30.glVertexAttribPointer(mAVerticalPositionLoc, NUM_COORDS_PER_VERTEX, 266 GLES30.GL_FLOAT, false, NUM_COORDS_PER_VERTEX * SIZEOF_FLOAT, mVertexBuffer); 267 268 GLES30.glEnableVertexAttribArray(mAVerticalTextureCoordLoc); 269 GLES30.glVertexAttribPointer(mAVerticalTextureCoordLoc, 2, 270 GLES30.GL_FLOAT, false, 2 * SIZEOF_FLOAT, mInvertedTexBuffer); 271 } 272 273 /** 274 * Sets the program to be used in the next rendering, and binds 275 * a texture to it 276 * 277 * @param programId The Id of the program 278 * @param textureId The Id of the texture to be bound 279 * @param textureTarget The type of texture that is being bound 280 */ setupProgram(int programId, int textureId, int textureTarget)281 private void setupProgram(int programId, int textureId, int textureTarget) { 282 GLES30.glUseProgram(programId); 283 GLHelper.checkGlErrors("glUseProgram"); 284 285 GLES30.glActiveTexture(GLES30.GL_TEXTURE0); 286 GLHelper.checkGlErrors("glActiveTexture"); 287 288 GLES30.glBindTexture(textureTarget, textureId); 289 GLHelper.checkGlErrors("glBindTexture"); 290 } 291 292 /** 293 * Renders to a framebuffer using the current active program 294 * 295 * @param framebufferId The Id of the framebuffer being rendered to 296 */ renderToFramebuffer(int framebufferId)297 private void renderToFramebuffer(int framebufferId) { 298 GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT); 299 GLHelper.checkGlErrors("glClear"); 300 301 GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, framebufferId); 302 GLHelper.checkGlErrors("glBindFramebuffer"); 303 304 GLES30.glViewport(0, 0, mWidth, mHeight); 305 GLHelper.checkGlErrors("glViewport"); 306 307 GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 308 FRAME_COORDS.length / NUM_COORDS_PER_VERTEX); 309 GLHelper.checkGlErrors("glDrawArrays"); 310 311 GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0); 312 } 313 314 /** 315 * Renders to a the GLSurface using the current active program 316 */ renderToSurface()317 private void renderToSurface() { 318 GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0); 319 GLHelper.checkGlErrors("glDrawArrays"); 320 321 GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT); 322 GLHelper.checkGlErrors("glDrawArrays"); 323 324 GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 325 FRAME_COORDS.length / NUM_COORDS_PER_VERTEX); 326 GLHelper.checkGlErrors("glDrawArrays"); 327 } 328 assertValidFramebufferStatus()329 private void assertValidFramebufferStatus() { 330 if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER) 331 != GLES30.GL_FRAMEBUFFER_COMPLETE) { 332 throw new RuntimeException( 333 "Failed to attach Framebuffer. Framebuffer status code is: " 334 + GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER)); 335 } 336 } 337 } 338