blob: c46fc20b3cc87947d3ae817973e50f1f6d31a736 [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 android.content.Context;
Mathias Agopian0449a402013-03-01 23:01:51 -080020import android.graphics.SurfaceTexture;
Jeff Brown4ccb8232014-01-16 22:16:42 -080021import android.hardware.display.DisplayManagerInternal;
22import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
Jeff Brown96307042012-07-27 15:51:34 -070023import android.opengl.EGL14;
24import android.opengl.EGLConfig;
25import android.opengl.EGLContext;
26import android.opengl.EGLDisplay;
27import android.opengl.EGLSurface;
Mathias Agopian0449a402013-03-01 23:01:51 -080028import android.opengl.GLES11Ext;
Vishnu Naire86bd982018-11-28 13:23:17 -080029import android.opengl.GLES20;
Dominik Laskowski3316a0a2019-01-25 02:56:41 -080030import android.os.IBinder;
Jeff Brown96307042012-07-27 15:51:34 -070031import android.util.Slog;
Peiyong Lin8f6d2782019-07-17 16:05:10 -070032import android.view.Display;
Jeff Brown96307042012-07-27 15:51:34 -070033import android.view.DisplayInfo;
34import android.view.Surface;
Vishnu Naire86bd982018-11-28 13:23:17 -080035import android.view.Surface.OutOfResourcesException;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080036import android.view.SurfaceControl;
Vishnu Naire86bd982018-11-28 13:23:17 -080037import android.view.SurfaceControl.Transaction;
Jeff Brown96307042012-07-27 15:51:34 -070038import android.view.SurfaceSession;
Jeff Brown96307042012-07-27 15:51:34 -070039
Jeff Brown4ccb8232014-01-16 22:16:42 -080040import com.android.server.LocalServices;
Vishnu Nair83537a72018-07-19 21:27:48 -070041import com.android.server.policy.WindowManagerPolicy;
Jeff Brown96307042012-07-27 15:51:34 -070042
Vishnu Naire86bd982018-11-28 13:23:17 -080043import libcore.io.Streams;
44
45import java.io.IOException;
46import java.io.InputStream;
47import java.io.InputStreamReader;
48import java.io.PrintWriter;
49import java.nio.ByteBuffer;
50import java.nio.ByteOrder;
51import java.nio.FloatBuffer;
52
Jeff Brown96307042012-07-27 15:51:34 -070053/**
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070054 * <p>
Jeff Brown96307042012-07-27 15:51:34 -070055 * Animates a screen transition from on to off or off to on by applying
56 * some GL transformations to a screenshot.
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070057 * </p><p>
Jeff Brown96307042012-07-27 15:51:34 -070058 * This component must only be created or accessed by the {@link Looper} thread
59 * that belongs to the {@link DisplayPowerController}.
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070060 * </p>
Jeff Brown96307042012-07-27 15:51:34 -070061 */
Michael Lentine0839adb2014-07-29 18:47:56 -070062final class ColorFade {
63 private static final String TAG = "ColorFade";
Jeff Brown96307042012-07-27 15:51:34 -070064
65 private static final boolean DEBUG = false;
66
67 // The layer for the electron beam surface.
68 // This is currently hardcoded to be one layer above the boot animation.
Vishnu Nair83537a72018-07-19 21:27:48 -070069 private static final int COLOR_FADE_LAYER = WindowManagerPolicy.COLOR_FADE_LAYER;
Jeff Brown96307042012-07-27 15:51:34 -070070
Jeff Brown78eb1222012-10-10 18:27:44 -070071 // The number of frames to draw when preparing the animation so that it will
72 // be ready to run smoothly. We use 3 frames because we are triple-buffered.
73 // See code for details.
74 private static final int DEJANK_FRAMES = 3;
75
Peiyong Lin8f6d2782019-07-17 16:05:10 -070076 private static final int EGL_GL_COLORSPACE_KHR = 0x309D;
77 private static final int EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490;
78
Jeff Brown037c33e2014-04-09 00:31:55 -070079 private final int mDisplayId;
80
Jeff Brown96307042012-07-27 15:51:34 -070081 // Set to true when the animation context has been fully prepared.
82 private boolean mPrepared;
Michael Lentined73854d2015-09-25 10:55:26 -070083 private boolean mCreatedResources;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070084 private int mMode;
Jeff Brown96307042012-07-27 15:51:34 -070085
Jeff Brown4ccb8232014-01-16 22:16:42 -080086 private final DisplayManagerInternal mDisplayManagerInternal;
Jeff Brown96307042012-07-27 15:51:34 -070087 private int mDisplayLayerStack; // layer stack associated with primary display
Jeff Brown96307042012-07-27 15:51:34 -070088 private int mDisplayWidth; // real width, not rotated
89 private int mDisplayHeight; // real height, not rotated
90 private SurfaceSession mSurfaceSession;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080091 private SurfaceControl mSurfaceControl;
Mathias Agopian86e1bc72013-03-13 17:48:22 -070092 private Surface mSurface;
Jeff Brown7f3994e2012-12-04 14:04:28 -080093 private NaturalSurfaceLayout mSurfaceLayout;
Jeff Brown96307042012-07-27 15:51:34 -070094 private EGLDisplay mEglDisplay;
95 private EGLConfig mEglConfig;
96 private EGLContext mEglContext;
97 private EGLSurface mEglSurface;
98 private boolean mSurfaceVisible;
Jeff Brown252c2062012-10-08 16:21:01 -070099 private float mSurfaceAlpha;
Peiyong Lin8f6d2782019-07-17 16:05:10 -0700100 private boolean mIsWideColor;
Jeff Brown96307042012-07-27 15:51:34 -0700101
102 // Texture names. We only use one texture, which contains the screenshot.
103 private final int[] mTexNames = new int[1];
104 private boolean mTexNamesGenerated;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700105 private final float mTexMatrix[] = new float[16];
Michael Lentine0839adb2014-07-29 18:47:56 -0700106 private final float mProjMatrix[] = new float[16];
107 private final int[] mGLBuffers = new int[2];
108 private int mTexCoordLoc, mVertexLoc, mTexUnitLoc, mProjMatrixLoc, mTexMatrixLoc;
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800109 private int mOpacityLoc, mGammaLoc;
Michael Lentine0839adb2014-07-29 18:47:56 -0700110 private int mProgram;
Jeff Brown96307042012-07-27 15:51:34 -0700111
112 // Vertex and corresponding texture coordinates.
113 // We have 4 2D vertices, so 8 elements. The vertices form a quad.
114 private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
115 private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
116
Jeff Brown252c2062012-10-08 16:21:01 -0700117 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700118 * Animates an color fade warming up.
Jeff Brown252c2062012-10-08 16:21:01 -0700119 */
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700120 public static final int MODE_WARM_UP = 0;
Jeff Brown252c2062012-10-08 16:21:01 -0700121
122 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700123 * Animates an color fade shutting off.
Jeff Brown252c2062012-10-08 16:21:01 -0700124 */
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700125 public static final int MODE_COOL_DOWN = 1;
Jeff Brown252c2062012-10-08 16:21:01 -0700126
127 /**
128 * Animates a simple dim layer to fade the contents of the screen in or out progressively.
129 */
130 public static final int MODE_FADE = 2;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700131
Michael Lentine0839adb2014-07-29 18:47:56 -0700132 public ColorFade(int displayId) {
Jeff Brown037c33e2014-04-09 00:31:55 -0700133 mDisplayId = displayId;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800134 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
Jeff Brown96307042012-07-27 15:51:34 -0700135 }
136
137 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700138 * Warms up the color fade in preparation for turning on or off.
Jeff Brown96307042012-07-27 15:51:34 -0700139 * This method prepares a GL context, and captures a screen shot.
140 *
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700141 * @param mode The desired mode for the upcoming animation.
Michael Lentine0839adb2014-07-29 18:47:56 -0700142 * @return True if the color fade is ready, false if it is uncontrollable.
Jeff Brown96307042012-07-27 15:51:34 -0700143 */
Michael Lentine0839adb2014-07-29 18:47:56 -0700144 public boolean prepare(Context context, int mode) {
Jeff Brown96307042012-07-27 15:51:34 -0700145 if (DEBUG) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700146 Slog.d(TAG, "prepare: mode=" + mode);
Jeff Brown96307042012-07-27 15:51:34 -0700147 }
148
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700149 mMode = mode;
Jeff Brown96307042012-07-27 15:51:34 -0700150
Jeff Brown7f3994e2012-12-04 14:04:28 -0800151 // Get the display size and layer stack.
Michael Lentine0839adb2014-07-29 18:47:56 -0700152 // This is not expected to change while the color fade surface is showing.
Jeff Brown037c33e2014-04-09 00:31:55 -0700153 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800154 mDisplayLayerStack = displayInfo.layerStack;
155 mDisplayWidth = displayInfo.getNaturalWidth();
156 mDisplayHeight = displayInfo.getNaturalHeight();
Jeff Brown96307042012-07-27 15:51:34 -0700157
158 // Prepare the surface for drawing.
Michael Lentine0839adb2014-07-29 18:47:56 -0700159 if (!(createSurface() && createEglContext() && createEglSurface() &&
160 captureScreenshotTextureAndSetViewport())) {
Jeff Brown96307042012-07-27 15:51:34 -0700161 dismiss();
162 return false;
163 }
164
Michael Lentine0839adb2014-07-29 18:47:56 -0700165 // Init GL
166 if (!attachEglContext()) {
167 return false;
168 }
169 try {
170 if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
171 detachEglContext();
172 dismiss();
173 return false;
174 }
175 } finally {
176 detachEglContext();
177 }
178
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700179 // Done.
Michael Lentined73854d2015-09-25 10:55:26 -0700180 mCreatedResources = true;
Jeff Brown96307042012-07-27 15:51:34 -0700181 mPrepared = true;
Jeff Brown78eb1222012-10-10 18:27:44 -0700182
183 // Dejanking optimization.
184 // Some GL drivers can introduce a lot of lag in the first few frames as they
185 // initialize their state and allocate graphics buffers for rendering.
186 // Work around this problem by rendering the first frame of the animation a few
187 // times. The rest of the animation should run smoothly thereafter.
188 // The frames we draw here aren't visible because we are essentially just
189 // painting the screenshot as-is.
190 if (mode == MODE_COOL_DOWN) {
191 for (int i = 0; i < DEJANK_FRAMES; i++) {
192 draw(1.0f);
193 }
194 }
Jeff Brown96307042012-07-27 15:51:34 -0700195 return true;
196 }
197
Michael Lentine0839adb2014-07-29 18:47:56 -0700198 private String readFile(Context context, int resourceId) {
199 try{
200 InputStream stream = context.getResources().openRawResource(resourceId);
201 return new String(Streams.readFully(new InputStreamReader(stream)));
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700202 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700203 catch (IOException e) {
204 Slog.e(TAG, "Unrecognized shader " + Integer.toString(resourceId));
205 throw new RuntimeException(e);
206 }
207 }
208
209 private int loadShader(Context context, int resourceId, int type) {
210 String source = readFile(context, resourceId);
211
212 int shader = GLES20.glCreateShader(type);
213
214 GLES20.glShaderSource(shader, source);
215 GLES20.glCompileShader(shader);
216
217 int[] compiled = new int[1];
218 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
219 if (compiled[0] == 0) {
220 Slog.e(TAG, "Could not compile shader " + shader + ", " + type + ":");
221 Slog.e(TAG, GLES20.glGetShaderSource(shader));
222 Slog.e(TAG, GLES20.glGetShaderInfoLog(shader));
223 GLES20.glDeleteShader(shader);
224 shader = 0;
225 }
226
227 return shader;
228 }
229
230 private boolean initGLShaders(Context context) {
231 int vshader = loadShader(context, com.android.internal.R.raw.color_fade_vert,
232 GLES20.GL_VERTEX_SHADER);
233 int fshader = loadShader(context, com.android.internal.R.raw.color_fade_frag,
234 GLES20.GL_FRAGMENT_SHADER);
Michael Wright5018df72014-10-08 17:46:09 -0700235 GLES20.glReleaseShaderCompiler();
Michael Lentine0839adb2014-07-29 18:47:56 -0700236 if (vshader == 0 || fshader == 0) return false;
237
238 mProgram = GLES20.glCreateProgram();
239
240 GLES20.glAttachShader(mProgram, vshader);
241 GLES20.glAttachShader(mProgram, fshader);
Michael Wright5018df72014-10-08 17:46:09 -0700242 GLES20.glDeleteShader(vshader);
243 GLES20.glDeleteShader(fshader);
Michael Lentine0839adb2014-07-29 18:47:56 -0700244
245 GLES20.glLinkProgram(mProgram);
246
247 mVertexLoc = GLES20.glGetAttribLocation(mProgram, "position");
248 mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "uv");
249
250 mProjMatrixLoc = GLES20.glGetUniformLocation(mProgram, "proj_matrix");
251 mTexMatrixLoc = GLES20.glGetUniformLocation(mProgram, "tex_matrix");
252
253 mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity");
254 mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma");
Michael Lentine0839adb2014-07-29 18:47:56 -0700255 mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit");
256
257 GLES20.glUseProgram(mProgram);
258 GLES20.glUniform1i(mTexUnitLoc, 0);
259 GLES20.glUseProgram(0);
260
261 return true;
262 }
263
Michael Wright5018df72014-10-08 17:46:09 -0700264 private void destroyGLShaders() {
265 GLES20.glDeleteProgram(mProgram);
266 checkGlErrors("glDeleteProgram");
267 }
268
Michael Lentine0839adb2014-07-29 18:47:56 -0700269 private boolean initGLBuffers() {
270 //Fill vertices
271 setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight);
272
273 // Setup GL Textures
274 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
275 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
276 GLES20.GL_NEAREST);
277 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
278 GLES20.GL_NEAREST);
279 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
280 GLES20.GL_CLAMP_TO_EDGE);
281 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
282 GLES20.GL_CLAMP_TO_EDGE);
283 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
284
285 // Setup GL Buffers
286 GLES20.glGenBuffers(2, mGLBuffers, 0);
287
288 // fill vertex buffer
289 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
290 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4,
291 mVertexBuffer, GLES20.GL_STATIC_DRAW);
292
293 // fill tex buffer
294 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
295 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4,
296 mTexCoordBuffer, GLES20.GL_STATIC_DRAW);
297
298 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
299
300 return true;
301 }
302
Michael Wright5018df72014-10-08 17:46:09 -0700303 private void destroyGLBuffers() {
304 GLES20.glDeleteBuffers(2, mGLBuffers, 0);
305 checkGlErrors("glDeleteBuffers");
306 }
307
Michael Lentine0839adb2014-07-29 18:47:56 -0700308 private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
309 if (DEBUG) {
310 Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
311 }
312 vtx.put(0, x);
313 vtx.put(1, y);
314 vtx.put(2, x);
315 vtx.put(3, y + h);
316 vtx.put(4, x + w);
317 vtx.put(5, y + h);
318 vtx.put(6, x + w);
319 vtx.put(7, y);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700320 }
321
Jeff Brown96307042012-07-27 15:51:34 -0700322 /**
Michael Lentined73854d2015-09-25 10:55:26 -0700323 * Dismisses the color fade animation resources.
324 *
325 * This function destroys the resources that are created for the color fade
326 * animation but does not clean up the surface.
327 */
328 public void dismissResources() {
329 if (DEBUG) {
330 Slog.d(TAG, "dismissResources");
331 }
332
333 if (mCreatedResources) {
334 attachEglContext();
335 try {
336 destroyScreenshotTexture();
337 destroyGLShaders();
338 destroyGLBuffers();
339 destroyEglSurface();
340 } finally {
341 detachEglContext();
342 }
343 // This is being called with no active context so shouldn't be
344 // needed but is safer to not change for now.
345 GLES20.glFlush();
346 mCreatedResources = false;
347 }
348 }
349
350 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700351 * Dismisses the color fade animation surface and cleans up.
Jeff Brown96307042012-07-27 15:51:34 -0700352 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700353 * To prevent stray photons from leaking out after the color fade has been
Jeff Brown96307042012-07-27 15:51:34 -0700354 * turned off, it is a good idea to defer dismissing the animation until the
Michael Lentine0839adb2014-07-29 18:47:56 -0700355 * color fade has been turned back on fully.
Jeff Brown96307042012-07-27 15:51:34 -0700356 */
357 public void dismiss() {
358 if (DEBUG) {
359 Slog.d(TAG, "dismiss");
360 }
361
Michael Wright5018df72014-10-08 17:46:09 -0700362 if (mPrepared) {
Michael Lentined73854d2015-09-25 10:55:26 -0700363 dismissResources();
Michael Wright5018df72014-10-08 17:46:09 -0700364 destroySurface();
Michael Wright5018df72014-10-08 17:46:09 -0700365 mPrepared = false;
366 }
Jeff Brown96307042012-07-27 15:51:34 -0700367 }
368
369 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700370 * Draws an animation frame showing the color fade activated at the
Jeff Brown96307042012-07-27 15:51:34 -0700371 * specified level.
372 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700373 * @param level The color fade level.
Jeff Brown96307042012-07-27 15:51:34 -0700374 * @return True if successful.
375 */
376 public boolean draw(float level) {
377 if (DEBUG) {
378 Slog.d(TAG, "drawFrame: level=" + level);
379 }
380
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700381 if (!mPrepared) {
382 return false;
383 }
384
Jeff Brown252c2062012-10-08 16:21:01 -0700385 if (mMode == MODE_FADE) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700386 return showSurface(1.0f - level);
387 }
388
Jeff Brown96307042012-07-27 15:51:34 -0700389 if (!attachEglContext()) {
390 return false;
391 }
392 try {
393 // Clear frame to solid black.
Michael Lentine0839adb2014-07-29 18:47:56 -0700394 GLES20.glClearColor(0f, 0f, 0f, 1f);
395 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Jeff Brown96307042012-07-27 15:51:34 -0700396
397 // Draw the frame.
Neil Fullere573aa92015-02-11 15:49:47 +0000398 double one_minus_level = 1 - level;
399 double cos = Math.cos(Math.PI * one_minus_level);
400 double sign = cos < 0 ? -1 : 1;
401 float opacity = (float) -Math.pow(one_minus_level, 2) + 1;
Neil Fullere573aa92015-02-11 15:49:47 +0000402 float gamma = (float) ((0.5d * sign * Math.pow(cos, 2) + 0.5d) * 0.9d + 0.1d);
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800403 drawFaded(opacity, 1.f / gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700404 if (checkGlErrors("drawFrame")) {
405 return false;
406 }
407
408 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
409 } finally {
410 detachEglContext();
411 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700412 return showSurface(1.0f);
Jeff Brown96307042012-07-27 15:51:34 -0700413 }
414
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800415 private void drawFaded(float opacity, float gamma) {
Jeff Brown96307042012-07-27 15:51:34 -0700416 if (DEBUG) {
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800417 Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700418 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700419 // Use shaders
420 GLES20.glUseProgram(mProgram);
Jeff Brown96307042012-07-27 15:51:34 -0700421
Michael Lentine0839adb2014-07-29 18:47:56 -0700422 // Set Uniforms
423 GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0);
424 GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
425 GLES20.glUniform1f(mOpacityLoc, opacity);
426 GLES20.glUniform1f(mGammaLoc, gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700427
Michael Lentine0839adb2014-07-29 18:47:56 -0700428 // Use textures
429 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
430 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
Jeff Brown96307042012-07-27 15:51:34 -0700431
Michael Lentine0839adb2014-07-29 18:47:56 -0700432 // draw the plane
433 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
434 GLES20.glEnableVertexAttribArray(mVertexLoc);
435 GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800436
Michael Lentine0839adb2014-07-29 18:47:56 -0700437 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
438 GLES20.glEnableVertexAttribArray(mTexCoordLoc);
439 GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700440
Michael Lentine0839adb2014-07-29 18:47:56 -0700441 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
Jeff Brown96307042012-07-27 15:51:34 -0700442
443 // clean up
Michael Lentine0839adb2014-07-29 18:47:56 -0700444 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
445 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700446 }
447
Michael Lentine0839adb2014-07-29 18:47:56 -0700448 private void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
449 mProjMatrix[0] = 2f / (right - left);
450 mProjMatrix[1] = 0;
451 mProjMatrix[2] = 0;
452 mProjMatrix[3] = 0;
453 mProjMatrix[4] = 0;
454 mProjMatrix[5] = 2f / (top - bottom);
455 mProjMatrix[6] = 0;
456 mProjMatrix[7] = 0;
457 mProjMatrix[8] = 0;
458 mProjMatrix[9] = 0;
459 mProjMatrix[10] = -2f / (zfar - znear);
460 mProjMatrix[11] = 0;
461 mProjMatrix[12] = -(right + left) / (right - left);
462 mProjMatrix[13] = -(top + bottom) / (top - bottom);
463 mProjMatrix[14] = -(zfar + znear) / (zfar - znear);
464 mProjMatrix[15] = 1f;
Jeff Brown96307042012-07-27 15:51:34 -0700465 }
466
467 private boolean captureScreenshotTextureAndSetViewport() {
Mathias Agopian0449a402013-03-01 23:01:51 -0800468 if (!attachEglContext()) {
Jeff Brown96307042012-07-27 15:51:34 -0700469 return false;
470 }
471 try {
Mathias Agopian0449a402013-03-01 23:01:51 -0800472 if (!mTexNamesGenerated) {
Michael Lentine0839adb2014-07-29 18:47:56 -0700473 GLES20.glGenTextures(1, mTexNames, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800474 if (checkGlErrors("glGenTextures")) {
Jeff Brown96307042012-07-27 15:51:34 -0700475 return false;
476 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800477 mTexNamesGenerated = true;
Jeff Brown96307042012-07-27 15:51:34 -0700478 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800479
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700480 final SurfaceTexture st = new SurfaceTexture(mTexNames[0]);
481 final Surface s = new Surface(st);
482 try {
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800483 final IBinder token = SurfaceControl.getInternalDisplayToken();
484 if (token == null) {
485 Slog.e(TAG,
486 "Failed to take screenshot because internal display is disconnected");
487 return false;
488 }
489
Peiyong Lin8f6d2782019-07-17 16:05:10 -0700490 mIsWideColor = SurfaceControl.getActiveColorMode(token)
491 == Display.COLOR_MODE_DISPLAY_P3;
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800492 SurfaceControl.screenshot(token, s);
Michael Wright2ed05132015-01-08 14:30:47 -0800493 st.updateTexImage();
494 st.getTransformMatrix(mTexMatrix);
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700495 } finally {
496 s.release();
Michael Wright2ed05132015-01-08 14:30:47 -0800497 st.release();
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700498 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800499
Mathias Agopian0449a402013-03-01 23:01:51 -0800500 // Set up texture coordinates for a quad.
501 // We might need to change this if the texture ends up being
502 // a different size from the display for some reason.
503 mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f);
504 mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f);
505 mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f);
506 mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
507
508 // Set up our viewport.
Michael Lentine0839adb2014-07-29 18:47:56 -0700509 GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
510 ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1);
Jeff Brown96307042012-07-27 15:51:34 -0700511 } finally {
Mathias Agopian0449a402013-03-01 23:01:51 -0800512 detachEglContext();
Jeff Brown96307042012-07-27 15:51:34 -0700513 }
514 return true;
515 }
516
517 private void destroyScreenshotTexture() {
518 if (mTexNamesGenerated) {
519 mTexNamesGenerated = false;
Michael Wright5018df72014-10-08 17:46:09 -0700520 GLES20.glDeleteTextures(1, mTexNames, 0);
521 checkGlErrors("glDeleteTextures");
Jeff Brown96307042012-07-27 15:51:34 -0700522 }
523 }
524
525 private boolean createEglContext() {
526 if (mEglDisplay == null) {
527 mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
528 if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
529 logEglError("eglGetDisplay");
530 return false;
531 }
532
533 int[] version = new int[2];
534 if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
535 mEglDisplay = null;
536 logEglError("eglInitialize");
537 return false;
538 }
539 }
540
541 if (mEglConfig == null) {
542 int[] eglConfigAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700543 EGL14.EGL_RENDERABLE_TYPE,
544 EGL14.EGL_OPENGL_ES2_BIT,
Jeff Brown96307042012-07-27 15:51:34 -0700545 EGL14.EGL_RED_SIZE, 8,
546 EGL14.EGL_GREEN_SIZE, 8,
547 EGL14.EGL_BLUE_SIZE, 8,
548 EGL14.EGL_ALPHA_SIZE, 8,
549 EGL14.EGL_NONE
550 };
551 int[] numEglConfigs = new int[1];
552 EGLConfig[] eglConfigs = new EGLConfig[1];
553 if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0,
554 eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) {
555 logEglError("eglChooseConfig");
556 return false;
557 }
Ivan.liu984827c2016-08-24 17:19:03 +0800558 if (numEglConfigs[0] <= 0) {
559 Slog.e(TAG, "no valid config found");
560 return false;
561 }
562
Jeff Brown96307042012-07-27 15:51:34 -0700563 mEglConfig = eglConfigs[0];
564 }
565
566 if (mEglContext == null) {
567 int[] eglContextAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700568 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
Jeff Brown96307042012-07-27 15:51:34 -0700569 EGL14.EGL_NONE
570 };
571 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
572 EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
573 if (mEglContext == null) {
574 logEglError("eglCreateContext");
575 return false;
576 }
577 }
578 return true;
579 }
580
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700581 private boolean createSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700582 if (mSurfaceSession == null) {
583 mSurfaceSession = new SurfaceSession();
584 }
585
Vishnu Naire86bd982018-11-28 13:23:17 -0800586 if (mSurfaceControl == null) {
587 Transaction t = new Transaction();
588 try {
589 final SurfaceControl.Builder builder =
590 new SurfaceControl.Builder(mSurfaceSession).setName("ColorFade");
591 if (mMode == MODE_FADE) {
Chavi Weingarten6ef9cc62019-02-07 16:28:45 +0000592 builder.setColorLayer();
Vishnu Naire86bd982018-11-28 13:23:17 -0800593 } else {
594 builder.setBufferSize(mDisplayWidth, mDisplayHeight);
Jeff Brown96307042012-07-27 15:51:34 -0700595 }
Vishnu Naire86bd982018-11-28 13:23:17 -0800596 mSurfaceControl = builder.build();
597 } catch (OutOfResourcesException ex) {
598 Slog.e(TAG, "Unable to create surface.", ex);
599 return false;
Jeff Brown96307042012-07-27 15:51:34 -0700600 }
Vishnu Naire86bd982018-11-28 13:23:17 -0800601
602 t.setLayerStack(mSurfaceControl, mDisplayLayerStack);
603 t.setWindowCrop(mSurfaceControl, mDisplayWidth, mDisplayHeight);
604 mSurface = new Surface();
605 mSurface.copyFrom(mSurfaceControl);
606
607 mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
608 mDisplayId, mSurfaceControl);
609 mSurfaceLayout.onDisplayTransaction(t);
610 t.apply();
Jeff Brown96307042012-07-27 15:51:34 -0700611 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700612 return true;
613 }
Jeff Brown96307042012-07-27 15:51:34 -0700614
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700615 private boolean createEglSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700616 if (mEglSurface == null) {
617 int[] eglSurfaceAttribList = new int[] {
Peiyong Lin8f6d2782019-07-17 16:05:10 -0700618 EGL14.EGL_NONE,
619 EGL14.EGL_NONE,
Jeff Brown96307042012-07-27 15:51:34 -0700620 EGL14.EGL_NONE
621 };
Peiyong Lin8f6d2782019-07-17 16:05:10 -0700622
623 // If the current display is in wide color, then so is the screenshot.
624 if (mIsWideColor) {
625 eglSurfaceAttribList[0] = EGL_GL_COLORSPACE_KHR;
626 eglSurfaceAttribList[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
627 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800628 // turn our SurfaceControl into a Surface
Jeff Brown96307042012-07-27 15:51:34 -0700629 mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
630 eglSurfaceAttribList, 0);
631 if (mEglSurface == null) {
632 logEglError("eglCreateWindowSurface");
633 return false;
634 }
635 }
636 return true;
637 }
638
639 private void destroyEglSurface() {
640 if (mEglSurface != null) {
641 if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) {
642 logEglError("eglDestroySurface");
643 }
644 mEglSurface = null;
645 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700646 }
Jeff Brown96307042012-07-27 15:51:34 -0700647
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700648 private void destroySurface() {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800649 if (mSurfaceControl != null) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800650 mSurfaceLayout.dispose();
651 mSurfaceLayout = null;
chaviwdd5bde02019-06-07 16:33:50 -0700652 new Transaction().remove(mSurfaceControl).apply();
653 mSurface.release();
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800654 mSurfaceControl = null;
Jeff Brown96307042012-07-27 15:51:34 -0700655 mSurfaceVisible = false;
Jeff Brown252c2062012-10-08 16:21:01 -0700656 mSurfaceAlpha = 0f;
Jeff Brown96307042012-07-27 15:51:34 -0700657 }
658 }
659
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700660 private boolean showSurface(float alpha) {
Jeff Brown252c2062012-10-08 16:21:01 -0700661 if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800662 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700663 try {
Michael Lentine0839adb2014-07-29 18:47:56 -0700664 mSurfaceControl.setLayer(COLOR_FADE_LAYER);
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800665 mSurfaceControl.setAlpha(alpha);
666 mSurfaceControl.show();
Jeff Brown96307042012-07-27 15:51:34 -0700667 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800668 SurfaceControl.closeTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700669 }
670 mSurfaceVisible = true;
Jeff Brown252c2062012-10-08 16:21:01 -0700671 mSurfaceAlpha = alpha;
Jeff Brown96307042012-07-27 15:51:34 -0700672 }
673 return true;
674 }
675
676 private boolean attachEglContext() {
677 if (mEglSurface == null) {
678 return false;
679 }
680 if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
681 logEglError("eglMakeCurrent");
682 return false;
683 }
684 return true;
685 }
686
687 private void detachEglContext() {
688 if (mEglDisplay != null) {
689 EGL14.eglMakeCurrent(mEglDisplay,
690 EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
691 }
692 }
693
Jeff Brown96307042012-07-27 15:51:34 -0700694 private static FloatBuffer createNativeFloatBuffer(int size) {
695 ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
696 bb.order(ByteOrder.nativeOrder());
697 return bb.asFloatBuffer();
698 }
699
700 private static void logEglError(String func) {
701 Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable());
702 }
703
704 private static boolean checkGlErrors(String func) {
705 return checkGlErrors(func, true);
706 }
707
708 private static boolean checkGlErrors(String func, boolean log) {
709 boolean hadError = false;
710 int error;
Michael Lentine0839adb2014-07-29 18:47:56 -0700711 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Jeff Brown96307042012-07-27 15:51:34 -0700712 if (log) {
713 Slog.e(TAG, func + " failed: error " + error, new Throwable());
714 }
715 hadError = true;
716 }
717 return hadError;
718 }
719
720 public void dump(PrintWriter pw) {
721 pw.println();
Michael Lentine0839adb2014-07-29 18:47:56 -0700722 pw.println("Color Fade State:");
Jeff Brown96307042012-07-27 15:51:34 -0700723 pw.println(" mPrepared=" + mPrepared);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700724 pw.println(" mMode=" + mMode);
Jeff Brown96307042012-07-27 15:51:34 -0700725 pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
Jeff Brown96307042012-07-27 15:51:34 -0700726 pw.println(" mDisplayWidth=" + mDisplayWidth);
727 pw.println(" mDisplayHeight=" + mDisplayHeight);
728 pw.println(" mSurfaceVisible=" + mSurfaceVisible);
Jeff Brown252c2062012-10-08 16:21:01 -0700729 pw.println(" mSurfaceAlpha=" + mSurfaceAlpha);
Jeff Brown96307042012-07-27 15:51:34 -0700730 }
Jeff Brown7f3994e2012-12-04 14:04:28 -0800731
732 /**
733 * Keeps a surface aligned with the natural orientation of the device.
734 * Updates the position and transformation of the matrix whenever the display
735 * is rotated. This is a little tricky because the display transaction
736 * callback can be invoked on any thread, not necessarily the thread that
Michael Lentine0839adb2014-07-29 18:47:56 -0700737 * owns the color fade.
Jeff Brown7f3994e2012-12-04 14:04:28 -0800738 */
739 private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
Jeff Brown4ccb8232014-01-16 22:16:42 -0800740 private final DisplayManagerInternal mDisplayManagerInternal;
Jeff Brown037c33e2014-04-09 00:31:55 -0700741 private final int mDisplayId;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800742 private SurfaceControl mSurfaceControl;
Jeff Brown7f3994e2012-12-04 14:04:28 -0800743
Jeff Brown4ccb8232014-01-16 22:16:42 -0800744 public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
Jeff Brown037c33e2014-04-09 00:31:55 -0700745 int displayId, SurfaceControl surfaceControl) {
Jeff Brown4ccb8232014-01-16 22:16:42 -0800746 mDisplayManagerInternal = displayManagerInternal;
Jeff Brown037c33e2014-04-09 00:31:55 -0700747 mDisplayId = displayId;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800748 mSurfaceControl = surfaceControl;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800749 mDisplayManagerInternal.registerDisplayTransactionListener(this);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800750 }
751
752 public void dispose() {
753 synchronized (this) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800754 mSurfaceControl = null;
Jeff Brown7f3994e2012-12-04 14:04:28 -0800755 }
Jeff Brown4ccb8232014-01-16 22:16:42 -0800756 mDisplayManagerInternal.unregisterDisplayTransactionListener(this);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800757 }
758
759 @Override
Vishnu Naire86bd982018-11-28 13:23:17 -0800760 public void onDisplayTransaction(Transaction t) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800761 synchronized (this) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800762 if (mSurfaceControl == null) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800763 return;
764 }
765
Jeff Brown037c33e2014-04-09 00:31:55 -0700766 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800767 switch (displayInfo.rotation) {
768 case Surface.ROTATION_0:
Vishnu Naire86bd982018-11-28 13:23:17 -0800769 t.setPosition(mSurfaceControl, 0, 0);
770 t.setMatrix(mSurfaceControl, 1, 0, 0, 1);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800771 break;
772 case Surface.ROTATION_90:
Vishnu Naire86bd982018-11-28 13:23:17 -0800773 t.setPosition(mSurfaceControl, 0, displayInfo.logicalHeight);
774 t.setMatrix(mSurfaceControl, 0, -1, 1, 0);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800775 break;
776 case Surface.ROTATION_180:
Vishnu Naire86bd982018-11-28 13:23:17 -0800777 t.setPosition(mSurfaceControl, displayInfo.logicalWidth,
Michael Lentine0839adb2014-07-29 18:47:56 -0700778 displayInfo.logicalHeight);
Vishnu Naire86bd982018-11-28 13:23:17 -0800779 t.setMatrix(mSurfaceControl, -1, 0, 0, -1);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800780 break;
781 case Surface.ROTATION_270:
Vishnu Naire86bd982018-11-28 13:23:17 -0800782 t.setPosition(mSurfaceControl, displayInfo.logicalWidth, 0);
783 t.setMatrix(mSurfaceControl, 0, 1, -1, 0);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800784 break;
785 }
786 }
787 }
788 }
Jeff Brown96307042012-07-27 15:51:34 -0700789}