blob: 33525fdc52d2a52269a7ccd86488d2ad89f6be48 [file] [log] [blame]
Jeff Brown96307042012-07-27 15:51:34 -07001/*
Michael Lentine0839adb2014-07-29 18:47:56 -07002 * Copyright (C) 2014 The Android Open Source Project
Jeff Brown96307042012-07-27 15:51:34 -07003 *
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
Jeff Brownad9ef192014-04-08 17:26:30 -070017package com.android.server.display;
Jeff Brown96307042012-07-27 15:51:34 -070018
Michael Lentine0839adb2014-07-29 18:47:56 -070019import java.io.IOException;
20import java.io.InputStream;
21import java.io.InputStreamReader;
Mathias Agopian0449a402013-03-01 23:01:51 -080022import java.io.PrintWriter;
23import java.nio.ByteBuffer;
24import java.nio.ByteOrder;
25import java.nio.FloatBuffer;
Jeff Brown7f3994e2012-12-04 14:04:28 -080026
Michael Lentine0839adb2014-07-29 18:47:56 -070027import android.content.Context;
Jeff Brown96307042012-07-27 15:51:34 -070028import android.graphics.PixelFormat;
Mathias Agopian0449a402013-03-01 23:01:51 -080029import android.graphics.SurfaceTexture;
Jeff Brown4ccb8232014-01-16 22:16:42 -080030import android.hardware.display.DisplayManagerInternal;
31import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
Jeff Brown96307042012-07-27 15:51:34 -070032import android.opengl.EGL14;
33import android.opengl.EGLConfig;
34import android.opengl.EGLContext;
35import android.opengl.EGLDisplay;
36import android.opengl.EGLSurface;
Michael Lentine0839adb2014-07-29 18:47:56 -070037import android.opengl.GLES20;
Mathias Agopian0449a402013-03-01 23:01:51 -080038import android.opengl.GLES11Ext;
Jeff Brown96307042012-07-27 15:51:34 -070039import android.util.Slog;
Jeff Brown96307042012-07-27 15:51:34 -070040import android.view.DisplayInfo;
Igor Murashkina86ab6402013-08-30 12:58:36 -070041import android.view.Surface.OutOfResourcesException;
Jeff Brown96307042012-07-27 15:51:34 -070042import android.view.Surface;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080043import android.view.SurfaceControl;
Jeff Brown96307042012-07-27 15:51:34 -070044import android.view.SurfaceSession;
Jeff Brown96307042012-07-27 15:51:34 -070045
Michael Lentine0839adb2014-07-29 18:47:56 -070046import libcore.io.Streams;
47
Jeff Brown4ccb8232014-01-16 22:16:42 -080048import com.android.server.LocalServices;
Adrian Roos28c25e22018-05-31 18:07:28 +020049import com.android.server.policy.WindowManagerPolicy;
Jeff Brown96307042012-07-27 15:51:34 -070050
51/**
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070052 * <p>
Jeff Brown96307042012-07-27 15:51:34 -070053 * Animates a screen transition from on to off or off to on by applying
54 * some GL transformations to a screenshot.
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070055 * </p><p>
Jeff Brown96307042012-07-27 15:51:34 -070056 * This component must only be created or accessed by the {@link Looper} thread
57 * that belongs to the {@link DisplayPowerController}.
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070058 * </p>
Jeff Brown96307042012-07-27 15:51:34 -070059 */
Michael Lentine0839adb2014-07-29 18:47:56 -070060final class ColorFade {
61 private static final String TAG = "ColorFade";
Jeff Brown96307042012-07-27 15:51:34 -070062
63 private static final boolean DEBUG = false;
64
65 // The layer for the electron beam surface.
66 // This is currently hardcoded to be one layer above the boot animation.
Adrian Roos28c25e22018-05-31 18:07:28 +020067 private static final int COLOR_FADE_LAYER = WindowManagerPolicy.COLOR_FADE_LAYER;
Jeff Brown96307042012-07-27 15:51:34 -070068
Jeff Brown78eb1222012-10-10 18:27:44 -070069 // The number of frames to draw when preparing the animation so that it will
70 // be ready to run smoothly. We use 3 frames because we are triple-buffered.
71 // See code for details.
72 private static final int DEJANK_FRAMES = 3;
73
Jeff Brown037c33e2014-04-09 00:31:55 -070074 private final int mDisplayId;
75
Jeff Brown96307042012-07-27 15:51:34 -070076 // Set to true when the animation context has been fully prepared.
77 private boolean mPrepared;
Michael Lentined73854d2015-09-25 10:55:26 -070078 private boolean mCreatedResources;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070079 private int mMode;
Jeff Brown96307042012-07-27 15:51:34 -070080
Jeff Brown4ccb8232014-01-16 22:16:42 -080081 private final DisplayManagerInternal mDisplayManagerInternal;
Jeff Brown96307042012-07-27 15:51:34 -070082 private int mDisplayLayerStack; // layer stack associated with primary display
Jeff Brown96307042012-07-27 15:51:34 -070083 private int mDisplayWidth; // real width, not rotated
84 private int mDisplayHeight; // real height, not rotated
85 private SurfaceSession mSurfaceSession;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080086 private SurfaceControl mSurfaceControl;
Mathias Agopian86e1bc72013-03-13 17:48:22 -070087 private Surface mSurface;
Jeff Brown7f3994e2012-12-04 14:04:28 -080088 private NaturalSurfaceLayout mSurfaceLayout;
Jeff Brown96307042012-07-27 15:51:34 -070089 private EGLDisplay mEglDisplay;
90 private EGLConfig mEglConfig;
91 private EGLContext mEglContext;
92 private EGLSurface mEglSurface;
93 private boolean mSurfaceVisible;
Jeff Brown252c2062012-10-08 16:21:01 -070094 private float mSurfaceAlpha;
Jeff Brown96307042012-07-27 15:51:34 -070095
96 // Texture names. We only use one texture, which contains the screenshot.
97 private final int[] mTexNames = new int[1];
98 private boolean mTexNamesGenerated;
Igor Murashkina86ab6402013-08-30 12:58:36 -070099 private final float mTexMatrix[] = new float[16];
Michael Lentine0839adb2014-07-29 18:47:56 -0700100 private final float mProjMatrix[] = new float[16];
101 private final int[] mGLBuffers = new int[2];
102 private int mTexCoordLoc, mVertexLoc, mTexUnitLoc, mProjMatrixLoc, mTexMatrixLoc;
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800103 private int mOpacityLoc, mGammaLoc;
Michael Lentine0839adb2014-07-29 18:47:56 -0700104 private int mProgram;
Jeff Brown96307042012-07-27 15:51:34 -0700105
106 // Vertex and corresponding texture coordinates.
107 // We have 4 2D vertices, so 8 elements. The vertices form a quad.
108 private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
109 private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
110
Jeff Brown252c2062012-10-08 16:21:01 -0700111 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700112 * Animates an color fade warming up.
Jeff Brown252c2062012-10-08 16:21:01 -0700113 */
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700114 public static final int MODE_WARM_UP = 0;
Jeff Brown252c2062012-10-08 16:21:01 -0700115
116 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700117 * Animates an color fade shutting off.
Jeff Brown252c2062012-10-08 16:21:01 -0700118 */
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700119 public static final int MODE_COOL_DOWN = 1;
Jeff Brown252c2062012-10-08 16:21:01 -0700120
121 /**
122 * Animates a simple dim layer to fade the contents of the screen in or out progressively.
123 */
124 public static final int MODE_FADE = 2;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700125
Michael Lentine0839adb2014-07-29 18:47:56 -0700126 public ColorFade(int displayId) {
Jeff Brown037c33e2014-04-09 00:31:55 -0700127 mDisplayId = displayId;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800128 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
Jeff Brown96307042012-07-27 15:51:34 -0700129 }
130
131 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700132 * Warms up the color fade in preparation for turning on or off.
Jeff Brown96307042012-07-27 15:51:34 -0700133 * This method prepares a GL context, and captures a screen shot.
134 *
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700135 * @param mode The desired mode for the upcoming animation.
Michael Lentine0839adb2014-07-29 18:47:56 -0700136 * @return True if the color fade is ready, false if it is uncontrollable.
Jeff Brown96307042012-07-27 15:51:34 -0700137 */
Michael Lentine0839adb2014-07-29 18:47:56 -0700138 public boolean prepare(Context context, int mode) {
Jeff Brown96307042012-07-27 15:51:34 -0700139 if (DEBUG) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700140 Slog.d(TAG, "prepare: mode=" + mode);
Jeff Brown96307042012-07-27 15:51:34 -0700141 }
142
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700143 mMode = mode;
Jeff Brown96307042012-07-27 15:51:34 -0700144
Jeff Brown7f3994e2012-12-04 14:04:28 -0800145 // Get the display size and layer stack.
Michael Lentine0839adb2014-07-29 18:47:56 -0700146 // This is not expected to change while the color fade surface is showing.
Jeff Brown037c33e2014-04-09 00:31:55 -0700147 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800148 mDisplayLayerStack = displayInfo.layerStack;
149 mDisplayWidth = displayInfo.getNaturalWidth();
150 mDisplayHeight = displayInfo.getNaturalHeight();
Jeff Brown96307042012-07-27 15:51:34 -0700151
152 // Prepare the surface for drawing.
Michael Lentine0839adb2014-07-29 18:47:56 -0700153 if (!(createSurface() && createEglContext() && createEglSurface() &&
154 captureScreenshotTextureAndSetViewport())) {
Jeff Brown96307042012-07-27 15:51:34 -0700155 dismiss();
156 return false;
157 }
158
Michael Lentine0839adb2014-07-29 18:47:56 -0700159 // Init GL
160 if (!attachEglContext()) {
161 return false;
162 }
163 try {
164 if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
165 detachEglContext();
166 dismiss();
167 return false;
168 }
169 } finally {
170 detachEglContext();
171 }
172
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700173 // Done.
Michael Lentined73854d2015-09-25 10:55:26 -0700174 mCreatedResources = true;
Jeff Brown96307042012-07-27 15:51:34 -0700175 mPrepared = true;
Jeff Brown78eb1222012-10-10 18:27:44 -0700176
177 // Dejanking optimization.
178 // Some GL drivers can introduce a lot of lag in the first few frames as they
179 // initialize their state and allocate graphics buffers for rendering.
180 // Work around this problem by rendering the first frame of the animation a few
181 // times. The rest of the animation should run smoothly thereafter.
182 // The frames we draw here aren't visible because we are essentially just
183 // painting the screenshot as-is.
184 if (mode == MODE_COOL_DOWN) {
185 for (int i = 0; i < DEJANK_FRAMES; i++) {
186 draw(1.0f);
187 }
188 }
Jeff Brown96307042012-07-27 15:51:34 -0700189 return true;
190 }
191
Michael Lentine0839adb2014-07-29 18:47:56 -0700192 private String readFile(Context context, int resourceId) {
193 try{
194 InputStream stream = context.getResources().openRawResource(resourceId);
195 return new String(Streams.readFully(new InputStreamReader(stream)));
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700196 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700197 catch (IOException e) {
198 Slog.e(TAG, "Unrecognized shader " + Integer.toString(resourceId));
199 throw new RuntimeException(e);
200 }
201 }
202
203 private int loadShader(Context context, int resourceId, int type) {
204 String source = readFile(context, resourceId);
205
206 int shader = GLES20.glCreateShader(type);
207
208 GLES20.glShaderSource(shader, source);
209 GLES20.glCompileShader(shader);
210
211 int[] compiled = new int[1];
212 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
213 if (compiled[0] == 0) {
214 Slog.e(TAG, "Could not compile shader " + shader + ", " + type + ":");
215 Slog.e(TAG, GLES20.glGetShaderSource(shader));
216 Slog.e(TAG, GLES20.glGetShaderInfoLog(shader));
217 GLES20.glDeleteShader(shader);
218 shader = 0;
219 }
220
221 return shader;
222 }
223
224 private boolean initGLShaders(Context context) {
225 int vshader = loadShader(context, com.android.internal.R.raw.color_fade_vert,
226 GLES20.GL_VERTEX_SHADER);
227 int fshader = loadShader(context, com.android.internal.R.raw.color_fade_frag,
228 GLES20.GL_FRAGMENT_SHADER);
Michael Wright5018df72014-10-08 17:46:09 -0700229 GLES20.glReleaseShaderCompiler();
Michael Lentine0839adb2014-07-29 18:47:56 -0700230 if (vshader == 0 || fshader == 0) return false;
231
232 mProgram = GLES20.glCreateProgram();
233
234 GLES20.glAttachShader(mProgram, vshader);
235 GLES20.glAttachShader(mProgram, fshader);
Michael Wright5018df72014-10-08 17:46:09 -0700236 GLES20.glDeleteShader(vshader);
237 GLES20.glDeleteShader(fshader);
Michael Lentine0839adb2014-07-29 18:47:56 -0700238
239 GLES20.glLinkProgram(mProgram);
240
241 mVertexLoc = GLES20.glGetAttribLocation(mProgram, "position");
242 mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "uv");
243
244 mProjMatrixLoc = GLES20.glGetUniformLocation(mProgram, "proj_matrix");
245 mTexMatrixLoc = GLES20.glGetUniformLocation(mProgram, "tex_matrix");
246
247 mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity");
248 mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma");
Michael Lentine0839adb2014-07-29 18:47:56 -0700249 mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit");
250
251 GLES20.glUseProgram(mProgram);
252 GLES20.glUniform1i(mTexUnitLoc, 0);
253 GLES20.glUseProgram(0);
254
255 return true;
256 }
257
Michael Wright5018df72014-10-08 17:46:09 -0700258 private void destroyGLShaders() {
259 GLES20.glDeleteProgram(mProgram);
260 checkGlErrors("glDeleteProgram");
261 }
262
Michael Lentine0839adb2014-07-29 18:47:56 -0700263 private boolean initGLBuffers() {
264 //Fill vertices
265 setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight);
266
267 // Setup GL Textures
268 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
269 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
270 GLES20.GL_NEAREST);
271 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
272 GLES20.GL_NEAREST);
273 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
274 GLES20.GL_CLAMP_TO_EDGE);
275 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
276 GLES20.GL_CLAMP_TO_EDGE);
277 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
278
279 // Setup GL Buffers
280 GLES20.glGenBuffers(2, mGLBuffers, 0);
281
282 // fill vertex buffer
283 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
284 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4,
285 mVertexBuffer, GLES20.GL_STATIC_DRAW);
286
287 // fill tex buffer
288 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
289 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4,
290 mTexCoordBuffer, GLES20.GL_STATIC_DRAW);
291
292 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
293
294 return true;
295 }
296
Michael Wright5018df72014-10-08 17:46:09 -0700297 private void destroyGLBuffers() {
298 GLES20.glDeleteBuffers(2, mGLBuffers, 0);
299 checkGlErrors("glDeleteBuffers");
300 }
301
Michael Lentine0839adb2014-07-29 18:47:56 -0700302 private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
303 if (DEBUG) {
304 Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
305 }
306 vtx.put(0, x);
307 vtx.put(1, y);
308 vtx.put(2, x);
309 vtx.put(3, y + h);
310 vtx.put(4, x + w);
311 vtx.put(5, y + h);
312 vtx.put(6, x + w);
313 vtx.put(7, y);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700314 }
315
Jeff Brown96307042012-07-27 15:51:34 -0700316 /**
Michael Lentined73854d2015-09-25 10:55:26 -0700317 * Dismisses the color fade animation resources.
318 *
319 * This function destroys the resources that are created for the color fade
320 * animation but does not clean up the surface.
321 */
322 public void dismissResources() {
323 if (DEBUG) {
324 Slog.d(TAG, "dismissResources");
325 }
326
327 if (mCreatedResources) {
328 attachEglContext();
329 try {
330 destroyScreenshotTexture();
331 destroyGLShaders();
332 destroyGLBuffers();
333 destroyEglSurface();
334 } finally {
335 detachEglContext();
336 }
337 // This is being called with no active context so shouldn't be
338 // needed but is safer to not change for now.
339 GLES20.glFlush();
340 mCreatedResources = false;
341 }
342 }
343
344 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700345 * Dismisses the color fade animation surface and cleans up.
Jeff Brown96307042012-07-27 15:51:34 -0700346 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700347 * To prevent stray photons from leaking out after the color fade has been
Jeff Brown96307042012-07-27 15:51:34 -0700348 * turned off, it is a good idea to defer dismissing the animation until the
Michael Lentine0839adb2014-07-29 18:47:56 -0700349 * color fade has been turned back on fully.
Jeff Brown96307042012-07-27 15:51:34 -0700350 */
351 public void dismiss() {
352 if (DEBUG) {
353 Slog.d(TAG, "dismiss");
354 }
355
Michael Wright5018df72014-10-08 17:46:09 -0700356 if (mPrepared) {
Michael Lentined73854d2015-09-25 10:55:26 -0700357 dismissResources();
Michael Wright5018df72014-10-08 17:46:09 -0700358 destroySurface();
Michael Wright5018df72014-10-08 17:46:09 -0700359 mPrepared = false;
360 }
Jeff Brown96307042012-07-27 15:51:34 -0700361 }
362
363 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700364 * Draws an animation frame showing the color fade activated at the
Jeff Brown96307042012-07-27 15:51:34 -0700365 * specified level.
366 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700367 * @param level The color fade level.
Jeff Brown96307042012-07-27 15:51:34 -0700368 * @return True if successful.
369 */
370 public boolean draw(float level) {
371 if (DEBUG) {
372 Slog.d(TAG, "drawFrame: level=" + level);
373 }
374
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700375 if (!mPrepared) {
376 return false;
377 }
378
Jeff Brown252c2062012-10-08 16:21:01 -0700379 if (mMode == MODE_FADE) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700380 return showSurface(1.0f - level);
381 }
382
Jeff Brown96307042012-07-27 15:51:34 -0700383 if (!attachEglContext()) {
384 return false;
385 }
386 try {
387 // Clear frame to solid black.
Michael Lentine0839adb2014-07-29 18:47:56 -0700388 GLES20.glClearColor(0f, 0f, 0f, 1f);
389 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Jeff Brown96307042012-07-27 15:51:34 -0700390
391 // Draw the frame.
Neil Fullere573aa92015-02-11 15:49:47 +0000392 double one_minus_level = 1 - level;
393 double cos = Math.cos(Math.PI * one_minus_level);
394 double sign = cos < 0 ? -1 : 1;
395 float opacity = (float) -Math.pow(one_minus_level, 2) + 1;
Neil Fullere573aa92015-02-11 15:49:47 +0000396 float gamma = (float) ((0.5d * sign * Math.pow(cos, 2) + 0.5d) * 0.9d + 0.1d);
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800397 drawFaded(opacity, 1.f / gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700398 if (checkGlErrors("drawFrame")) {
399 return false;
400 }
401
402 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
403 } finally {
404 detachEglContext();
405 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700406 return showSurface(1.0f);
Jeff Brown96307042012-07-27 15:51:34 -0700407 }
408
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800409 private void drawFaded(float opacity, float gamma) {
Jeff Brown96307042012-07-27 15:51:34 -0700410 if (DEBUG) {
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800411 Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700412 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700413 // Use shaders
414 GLES20.glUseProgram(mProgram);
Jeff Brown96307042012-07-27 15:51:34 -0700415
Michael Lentine0839adb2014-07-29 18:47:56 -0700416 // Set Uniforms
417 GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0);
418 GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
419 GLES20.glUniform1f(mOpacityLoc, opacity);
420 GLES20.glUniform1f(mGammaLoc, gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700421
Michael Lentine0839adb2014-07-29 18:47:56 -0700422 // Use textures
423 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
424 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
Jeff Brown96307042012-07-27 15:51:34 -0700425
Michael Lentine0839adb2014-07-29 18:47:56 -0700426 // draw the plane
427 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
428 GLES20.glEnableVertexAttribArray(mVertexLoc);
429 GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800430
Michael Lentine0839adb2014-07-29 18:47:56 -0700431 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
432 GLES20.glEnableVertexAttribArray(mTexCoordLoc);
433 GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700434
Michael Lentine0839adb2014-07-29 18:47:56 -0700435 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
Jeff Brown96307042012-07-27 15:51:34 -0700436
437 // clean up
Michael Lentine0839adb2014-07-29 18:47:56 -0700438 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
439 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700440 }
441
Michael Lentine0839adb2014-07-29 18:47:56 -0700442 private void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
443 mProjMatrix[0] = 2f / (right - left);
444 mProjMatrix[1] = 0;
445 mProjMatrix[2] = 0;
446 mProjMatrix[3] = 0;
447 mProjMatrix[4] = 0;
448 mProjMatrix[5] = 2f / (top - bottom);
449 mProjMatrix[6] = 0;
450 mProjMatrix[7] = 0;
451 mProjMatrix[8] = 0;
452 mProjMatrix[9] = 0;
453 mProjMatrix[10] = -2f / (zfar - znear);
454 mProjMatrix[11] = 0;
455 mProjMatrix[12] = -(right + left) / (right - left);
456 mProjMatrix[13] = -(top + bottom) / (top - bottom);
457 mProjMatrix[14] = -(zfar + znear) / (zfar - znear);
458 mProjMatrix[15] = 1f;
Jeff Brown96307042012-07-27 15:51:34 -0700459 }
460
461 private boolean captureScreenshotTextureAndSetViewport() {
Mathias Agopian0449a402013-03-01 23:01:51 -0800462 if (!attachEglContext()) {
Jeff Brown96307042012-07-27 15:51:34 -0700463 return false;
464 }
465 try {
Mathias Agopian0449a402013-03-01 23:01:51 -0800466 if (!mTexNamesGenerated) {
Michael Lentine0839adb2014-07-29 18:47:56 -0700467 GLES20.glGenTextures(1, mTexNames, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800468 if (checkGlErrors("glGenTextures")) {
Jeff Brown96307042012-07-27 15:51:34 -0700469 return false;
470 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800471 mTexNamesGenerated = true;
Jeff Brown96307042012-07-27 15:51:34 -0700472 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800473
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700474 final SurfaceTexture st = new SurfaceTexture(mTexNames[0]);
475 final Surface s = new Surface(st);
476 try {
477 SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
478 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), s);
Michael Wright2ed05132015-01-08 14:30:47 -0800479 st.updateTexImage();
480 st.getTransformMatrix(mTexMatrix);
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700481 } finally {
482 s.release();
Michael Wright2ed05132015-01-08 14:30:47 -0800483 st.release();
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700484 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800485
Mathias Agopian0449a402013-03-01 23:01:51 -0800486 // Set up texture coordinates for a quad.
487 // We might need to change this if the texture ends up being
488 // a different size from the display for some reason.
489 mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f);
490 mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f);
491 mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f);
492 mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
493
494 // Set up our viewport.
Michael Lentine0839adb2014-07-29 18:47:56 -0700495 GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
496 ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1);
Jeff Brown96307042012-07-27 15:51:34 -0700497 } finally {
Mathias Agopian0449a402013-03-01 23:01:51 -0800498 detachEglContext();
Jeff Brown96307042012-07-27 15:51:34 -0700499 }
500 return true;
501 }
502
503 private void destroyScreenshotTexture() {
504 if (mTexNamesGenerated) {
505 mTexNamesGenerated = false;
Michael Wright5018df72014-10-08 17:46:09 -0700506 GLES20.glDeleteTextures(1, mTexNames, 0);
507 checkGlErrors("glDeleteTextures");
Jeff Brown96307042012-07-27 15:51:34 -0700508 }
509 }
510
511 private boolean createEglContext() {
512 if (mEglDisplay == null) {
513 mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
514 if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
515 logEglError("eglGetDisplay");
516 return false;
517 }
518
519 int[] version = new int[2];
520 if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
521 mEglDisplay = null;
522 logEglError("eglInitialize");
523 return false;
524 }
525 }
526
527 if (mEglConfig == null) {
528 int[] eglConfigAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700529 EGL14.EGL_RENDERABLE_TYPE,
530 EGL14.EGL_OPENGL_ES2_BIT,
Jeff Brown96307042012-07-27 15:51:34 -0700531 EGL14.EGL_RED_SIZE, 8,
532 EGL14.EGL_GREEN_SIZE, 8,
533 EGL14.EGL_BLUE_SIZE, 8,
534 EGL14.EGL_ALPHA_SIZE, 8,
535 EGL14.EGL_NONE
536 };
537 int[] numEglConfigs = new int[1];
538 EGLConfig[] eglConfigs = new EGLConfig[1];
539 if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0,
540 eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) {
541 logEglError("eglChooseConfig");
542 return false;
543 }
Ivan.liu984827c2016-08-24 17:19:03 +0800544 if (numEglConfigs[0] <= 0) {
545 Slog.e(TAG, "no valid config found");
546 return false;
547 }
548
Jeff Brown96307042012-07-27 15:51:34 -0700549 mEglConfig = eglConfigs[0];
550 }
551
552 if (mEglContext == null) {
553 int[] eglContextAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700554 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
Jeff Brown96307042012-07-27 15:51:34 -0700555 EGL14.EGL_NONE
556 };
557 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
558 EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
559 if (mEglContext == null) {
560 logEglError("eglCreateContext");
561 return false;
562 }
563 }
564 return true;
565 }
566
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700567 private boolean createSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700568 if (mSurfaceSession == null) {
569 mSurfaceSession = new SurfaceSession();
570 }
571
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800572 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700573 try {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800574 if (mSurfaceControl == null) {
Jeff Brown96307042012-07-27 15:51:34 -0700575 try {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700576 int flags;
Jeff Brown252c2062012-10-08 16:21:01 -0700577 if (mMode == MODE_FADE) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800578 flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700579 } else {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800580 flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700581 }
Robert Carre625fcf2017-09-01 12:36:28 -0700582 mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
583 .setName("ColorFade")
584 .setSize(mDisplayWidth, mDisplayHeight)
585 .setFlags(flags)
586 .build();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700587 } catch (OutOfResourcesException ex) {
Jeff Brown96307042012-07-27 15:51:34 -0700588 Slog.e(TAG, "Unable to create surface.", ex);
589 return false;
590 }
yang.xa.liu40d73a72015-12-18 16:40:31 +0800591
592 mSurfaceControl.setLayerStack(mDisplayLayerStack);
593 mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
594 mSurface = new Surface();
595 mSurface.copyFrom(mSurfaceControl);
596
597 mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
598 mDisplayId, mSurfaceControl);
599 mSurfaceLayout.onDisplayTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700600 }
Jeff Brown96307042012-07-27 15:51:34 -0700601 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800602 SurfaceControl.closeTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700603 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700604 return true;
605 }
Jeff Brown96307042012-07-27 15:51:34 -0700606
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700607 private boolean createEglSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700608 if (mEglSurface == null) {
609 int[] eglSurfaceAttribList = new int[] {
610 EGL14.EGL_NONE
611 };
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800612 // turn our SurfaceControl into a Surface
Jeff Brown96307042012-07-27 15:51:34 -0700613 mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
614 eglSurfaceAttribList, 0);
615 if (mEglSurface == null) {
616 logEglError("eglCreateWindowSurface");
617 return false;
618 }
619 }
620 return true;
621 }
622
623 private void destroyEglSurface() {
624 if (mEglSurface != null) {
625 if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) {
626 logEglError("eglDestroySurface");
627 }
628 mEglSurface = null;
629 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700630 }
Jeff Brown96307042012-07-27 15:51:34 -0700631
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700632 private void destroySurface() {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800633 if (mSurfaceControl != null) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800634 mSurfaceLayout.dispose();
635 mSurfaceLayout = null;
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800636 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700637 try {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800638 mSurfaceControl.destroy();
639 mSurface.release();
Jeff Brown96307042012-07-27 15:51:34 -0700640 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800641 SurfaceControl.closeTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700642 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800643 mSurfaceControl = null;
Jeff Brown96307042012-07-27 15:51:34 -0700644 mSurfaceVisible = false;
Jeff Brown252c2062012-10-08 16:21:01 -0700645 mSurfaceAlpha = 0f;
Jeff Brown96307042012-07-27 15:51:34 -0700646 }
647 }
648
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700649 private boolean showSurface(float alpha) {
Jeff Brown252c2062012-10-08 16:21:01 -0700650 if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800651 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700652 try {
Michael Lentine0839adb2014-07-29 18:47:56 -0700653 mSurfaceControl.setLayer(COLOR_FADE_LAYER);
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800654 mSurfaceControl.setAlpha(alpha);
655 mSurfaceControl.show();
Jeff Brown96307042012-07-27 15:51:34 -0700656 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800657 SurfaceControl.closeTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700658 }
659 mSurfaceVisible = true;
Jeff Brown252c2062012-10-08 16:21:01 -0700660 mSurfaceAlpha = alpha;
Jeff Brown96307042012-07-27 15:51:34 -0700661 }
662 return true;
663 }
664
665 private boolean attachEglContext() {
666 if (mEglSurface == null) {
667 return false;
668 }
669 if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
670 logEglError("eglMakeCurrent");
671 return false;
672 }
673 return true;
674 }
675
676 private void detachEglContext() {
677 if (mEglDisplay != null) {
678 EGL14.eglMakeCurrent(mEglDisplay,
679 EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
680 }
681 }
682
Jeff Brown96307042012-07-27 15:51:34 -0700683 private static FloatBuffer createNativeFloatBuffer(int size) {
684 ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
685 bb.order(ByteOrder.nativeOrder());
686 return bb.asFloatBuffer();
687 }
688
689 private static void logEglError(String func) {
690 Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable());
691 }
692
693 private static boolean checkGlErrors(String func) {
694 return checkGlErrors(func, true);
695 }
696
697 private static boolean checkGlErrors(String func, boolean log) {
698 boolean hadError = false;
699 int error;
Michael Lentine0839adb2014-07-29 18:47:56 -0700700 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Jeff Brown96307042012-07-27 15:51:34 -0700701 if (log) {
702 Slog.e(TAG, func + " failed: error " + error, new Throwable());
703 }
704 hadError = true;
705 }
706 return hadError;
707 }
708
709 public void dump(PrintWriter pw) {
710 pw.println();
Michael Lentine0839adb2014-07-29 18:47:56 -0700711 pw.println("Color Fade State:");
Jeff Brown96307042012-07-27 15:51:34 -0700712 pw.println(" mPrepared=" + mPrepared);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700713 pw.println(" mMode=" + mMode);
Jeff Brown96307042012-07-27 15:51:34 -0700714 pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
Jeff Brown96307042012-07-27 15:51:34 -0700715 pw.println(" mDisplayWidth=" + mDisplayWidth);
716 pw.println(" mDisplayHeight=" + mDisplayHeight);
717 pw.println(" mSurfaceVisible=" + mSurfaceVisible);
Jeff Brown252c2062012-10-08 16:21:01 -0700718 pw.println(" mSurfaceAlpha=" + mSurfaceAlpha);
Jeff Brown96307042012-07-27 15:51:34 -0700719 }
Jeff Brown7f3994e2012-12-04 14:04:28 -0800720
721 /**
722 * Keeps a surface aligned with the natural orientation of the device.
723 * Updates the position and transformation of the matrix whenever the display
724 * is rotated. This is a little tricky because the display transaction
725 * callback can be invoked on any thread, not necessarily the thread that
Michael Lentine0839adb2014-07-29 18:47:56 -0700726 * owns the color fade.
Jeff Brown7f3994e2012-12-04 14:04:28 -0800727 */
728 private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
Jeff Brown4ccb8232014-01-16 22:16:42 -0800729 private final DisplayManagerInternal mDisplayManagerInternal;
Jeff Brown037c33e2014-04-09 00:31:55 -0700730 private final int mDisplayId;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800731 private SurfaceControl mSurfaceControl;
Jeff Brown7f3994e2012-12-04 14:04:28 -0800732
Jeff Brown4ccb8232014-01-16 22:16:42 -0800733 public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
Jeff Brown037c33e2014-04-09 00:31:55 -0700734 int displayId, SurfaceControl surfaceControl) {
Jeff Brown4ccb8232014-01-16 22:16:42 -0800735 mDisplayManagerInternal = displayManagerInternal;
Jeff Brown037c33e2014-04-09 00:31:55 -0700736 mDisplayId = displayId;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800737 mSurfaceControl = surfaceControl;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800738 mDisplayManagerInternal.registerDisplayTransactionListener(this);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800739 }
740
741 public void dispose() {
742 synchronized (this) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800743 mSurfaceControl = null;
Jeff Brown7f3994e2012-12-04 14:04:28 -0800744 }
Jeff Brown4ccb8232014-01-16 22:16:42 -0800745 mDisplayManagerInternal.unregisterDisplayTransactionListener(this);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800746 }
747
748 @Override
749 public void onDisplayTransaction() {
750 synchronized (this) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800751 if (mSurfaceControl == null) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800752 return;
753 }
754
Jeff Brown037c33e2014-04-09 00:31:55 -0700755 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800756 switch (displayInfo.rotation) {
757 case Surface.ROTATION_0:
Mathias Agopian29479eb2013-02-14 14:36:04 -0800758 mSurfaceControl.setPosition(0, 0);
759 mSurfaceControl.setMatrix(1, 0, 0, 1);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800760 break;
761 case Surface.ROTATION_90:
Mathias Agopian29479eb2013-02-14 14:36:04 -0800762 mSurfaceControl.setPosition(0, displayInfo.logicalHeight);
763 mSurfaceControl.setMatrix(0, -1, 1, 0);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800764 break;
765 case Surface.ROTATION_180:
Michael Lentine0839adb2014-07-29 18:47:56 -0700766 mSurfaceControl.setPosition(displayInfo.logicalWidth,
767 displayInfo.logicalHeight);
Mathias Agopian29479eb2013-02-14 14:36:04 -0800768 mSurfaceControl.setMatrix(-1, 0, 0, -1);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800769 break;
770 case Surface.ROTATION_270:
Mathias Agopian29479eb2013-02-14 14:36:04 -0800771 mSurfaceControl.setPosition(displayInfo.logicalWidth, 0);
772 mSurfaceControl.setMatrix(0, 1, -1, 0);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800773 break;
774 }
775 }
776 }
777 }
Jeff Brown96307042012-07-27 15:51:34 -0700778}