blob: ec2b0c0a6830738cdd6299de1768d6480d4233ab [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
chaviw619da692019-06-10 15:39:40 -0700117 private final Transaction mTransaction = new Transaction();
118
Jeff Brown252c2062012-10-08 16:21:01 -0700119 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700120 * Animates an color fade warming up.
Jeff Brown252c2062012-10-08 16:21:01 -0700121 */
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700122 public static final int MODE_WARM_UP = 0;
Jeff Brown252c2062012-10-08 16:21:01 -0700123
124 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700125 * Animates an color fade shutting off.
Jeff Brown252c2062012-10-08 16:21:01 -0700126 */
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700127 public static final int MODE_COOL_DOWN = 1;
Jeff Brown252c2062012-10-08 16:21:01 -0700128
129 /**
130 * Animates a simple dim layer to fade the contents of the screen in or out progressively.
131 */
132 public static final int MODE_FADE = 2;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700133
Michael Lentine0839adb2014-07-29 18:47:56 -0700134 public ColorFade(int displayId) {
Jeff Brown037c33e2014-04-09 00:31:55 -0700135 mDisplayId = displayId;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800136 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
Jeff Brown96307042012-07-27 15:51:34 -0700137 }
138
139 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700140 * Warms up the color fade in preparation for turning on or off.
Jeff Brown96307042012-07-27 15:51:34 -0700141 * This method prepares a GL context, and captures a screen shot.
142 *
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700143 * @param mode The desired mode for the upcoming animation.
Michael Lentine0839adb2014-07-29 18:47:56 -0700144 * @return True if the color fade is ready, false if it is uncontrollable.
Jeff Brown96307042012-07-27 15:51:34 -0700145 */
Michael Lentine0839adb2014-07-29 18:47:56 -0700146 public boolean prepare(Context context, int mode) {
Jeff Brown96307042012-07-27 15:51:34 -0700147 if (DEBUG) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700148 Slog.d(TAG, "prepare: mode=" + mode);
Jeff Brown96307042012-07-27 15:51:34 -0700149 }
150
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700151 mMode = mode;
Jeff Brown96307042012-07-27 15:51:34 -0700152
Jeff Brown7f3994e2012-12-04 14:04:28 -0800153 // Get the display size and layer stack.
Michael Lentine0839adb2014-07-29 18:47:56 -0700154 // This is not expected to change while the color fade surface is showing.
Jeff Brown037c33e2014-04-09 00:31:55 -0700155 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800156 mDisplayLayerStack = displayInfo.layerStack;
157 mDisplayWidth = displayInfo.getNaturalWidth();
158 mDisplayHeight = displayInfo.getNaturalHeight();
Jeff Brown96307042012-07-27 15:51:34 -0700159
160 // Prepare the surface for drawing.
Michael Lentine0839adb2014-07-29 18:47:56 -0700161 if (!(createSurface() && createEglContext() && createEglSurface() &&
162 captureScreenshotTextureAndSetViewport())) {
Jeff Brown96307042012-07-27 15:51:34 -0700163 dismiss();
164 return false;
165 }
166
Michael Lentine0839adb2014-07-29 18:47:56 -0700167 // Init GL
168 if (!attachEglContext()) {
169 return false;
170 }
171 try {
172 if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
173 detachEglContext();
174 dismiss();
175 return false;
176 }
177 } finally {
178 detachEglContext();
179 }
180
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700181 // Done.
Michael Lentined73854d2015-09-25 10:55:26 -0700182 mCreatedResources = true;
Jeff Brown96307042012-07-27 15:51:34 -0700183 mPrepared = true;
Jeff Brown78eb1222012-10-10 18:27:44 -0700184
185 // Dejanking optimization.
186 // Some GL drivers can introduce a lot of lag in the first few frames as they
187 // initialize their state and allocate graphics buffers for rendering.
188 // Work around this problem by rendering the first frame of the animation a few
189 // times. The rest of the animation should run smoothly thereafter.
190 // The frames we draw here aren't visible because we are essentially just
191 // painting the screenshot as-is.
192 if (mode == MODE_COOL_DOWN) {
193 for (int i = 0; i < DEJANK_FRAMES; i++) {
194 draw(1.0f);
195 }
196 }
Jeff Brown96307042012-07-27 15:51:34 -0700197 return true;
198 }
199
Michael Lentine0839adb2014-07-29 18:47:56 -0700200 private String readFile(Context context, int resourceId) {
201 try{
202 InputStream stream = context.getResources().openRawResource(resourceId);
203 return new String(Streams.readFully(new InputStreamReader(stream)));
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700204 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700205 catch (IOException e) {
206 Slog.e(TAG, "Unrecognized shader " + Integer.toString(resourceId));
207 throw new RuntimeException(e);
208 }
209 }
210
211 private int loadShader(Context context, int resourceId, int type) {
212 String source = readFile(context, resourceId);
213
214 int shader = GLES20.glCreateShader(type);
215
216 GLES20.glShaderSource(shader, source);
217 GLES20.glCompileShader(shader);
218
219 int[] compiled = new int[1];
220 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
221 if (compiled[0] == 0) {
222 Slog.e(TAG, "Could not compile shader " + shader + ", " + type + ":");
223 Slog.e(TAG, GLES20.glGetShaderSource(shader));
224 Slog.e(TAG, GLES20.glGetShaderInfoLog(shader));
225 GLES20.glDeleteShader(shader);
226 shader = 0;
227 }
228
229 return shader;
230 }
231
232 private boolean initGLShaders(Context context) {
233 int vshader = loadShader(context, com.android.internal.R.raw.color_fade_vert,
234 GLES20.GL_VERTEX_SHADER);
235 int fshader = loadShader(context, com.android.internal.R.raw.color_fade_frag,
236 GLES20.GL_FRAGMENT_SHADER);
Michael Wright5018df72014-10-08 17:46:09 -0700237 GLES20.glReleaseShaderCompiler();
Michael Lentine0839adb2014-07-29 18:47:56 -0700238 if (vshader == 0 || fshader == 0) return false;
239
240 mProgram = GLES20.glCreateProgram();
241
242 GLES20.glAttachShader(mProgram, vshader);
243 GLES20.glAttachShader(mProgram, fshader);
Michael Wright5018df72014-10-08 17:46:09 -0700244 GLES20.glDeleteShader(vshader);
245 GLES20.glDeleteShader(fshader);
Michael Lentine0839adb2014-07-29 18:47:56 -0700246
247 GLES20.glLinkProgram(mProgram);
248
249 mVertexLoc = GLES20.glGetAttribLocation(mProgram, "position");
250 mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "uv");
251
252 mProjMatrixLoc = GLES20.glGetUniformLocation(mProgram, "proj_matrix");
253 mTexMatrixLoc = GLES20.glGetUniformLocation(mProgram, "tex_matrix");
254
255 mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity");
256 mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma");
Michael Lentine0839adb2014-07-29 18:47:56 -0700257 mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit");
258
259 GLES20.glUseProgram(mProgram);
260 GLES20.glUniform1i(mTexUnitLoc, 0);
261 GLES20.glUseProgram(0);
262
263 return true;
264 }
265
Michael Wright5018df72014-10-08 17:46:09 -0700266 private void destroyGLShaders() {
267 GLES20.glDeleteProgram(mProgram);
268 checkGlErrors("glDeleteProgram");
269 }
270
Michael Lentine0839adb2014-07-29 18:47:56 -0700271 private boolean initGLBuffers() {
272 //Fill vertices
273 setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight);
274
275 // Setup GL Textures
276 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
277 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
278 GLES20.GL_NEAREST);
279 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
280 GLES20.GL_NEAREST);
281 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
282 GLES20.GL_CLAMP_TO_EDGE);
283 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
284 GLES20.GL_CLAMP_TO_EDGE);
285 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
286
287 // Setup GL Buffers
288 GLES20.glGenBuffers(2, mGLBuffers, 0);
289
290 // fill vertex buffer
291 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
292 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4,
293 mVertexBuffer, GLES20.GL_STATIC_DRAW);
294
295 // fill tex buffer
296 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
297 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4,
298 mTexCoordBuffer, GLES20.GL_STATIC_DRAW);
299
300 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
301
302 return true;
303 }
304
Michael Wright5018df72014-10-08 17:46:09 -0700305 private void destroyGLBuffers() {
306 GLES20.glDeleteBuffers(2, mGLBuffers, 0);
307 checkGlErrors("glDeleteBuffers");
308 }
309
Michael Lentine0839adb2014-07-29 18:47:56 -0700310 private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
311 if (DEBUG) {
312 Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
313 }
314 vtx.put(0, x);
315 vtx.put(1, y);
316 vtx.put(2, x);
317 vtx.put(3, y + h);
318 vtx.put(4, x + w);
319 vtx.put(5, y + h);
320 vtx.put(6, x + w);
321 vtx.put(7, y);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700322 }
323
Jeff Brown96307042012-07-27 15:51:34 -0700324 /**
Michael Lentined73854d2015-09-25 10:55:26 -0700325 * Dismisses the color fade animation resources.
326 *
327 * This function destroys the resources that are created for the color fade
328 * animation but does not clean up the surface.
329 */
330 public void dismissResources() {
331 if (DEBUG) {
332 Slog.d(TAG, "dismissResources");
333 }
334
335 if (mCreatedResources) {
336 attachEglContext();
337 try {
338 destroyScreenshotTexture();
339 destroyGLShaders();
340 destroyGLBuffers();
341 destroyEglSurface();
342 } finally {
343 detachEglContext();
344 }
345 // This is being called with no active context so shouldn't be
346 // needed but is safer to not change for now.
347 GLES20.glFlush();
348 mCreatedResources = false;
349 }
350 }
351
352 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700353 * Dismisses the color fade animation surface and cleans up.
Jeff Brown96307042012-07-27 15:51:34 -0700354 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700355 * To prevent stray photons from leaking out after the color fade has been
Jeff Brown96307042012-07-27 15:51:34 -0700356 * turned off, it is a good idea to defer dismissing the animation until the
Michael Lentine0839adb2014-07-29 18:47:56 -0700357 * color fade has been turned back on fully.
Jeff Brown96307042012-07-27 15:51:34 -0700358 */
359 public void dismiss() {
360 if (DEBUG) {
361 Slog.d(TAG, "dismiss");
362 }
363
Michael Wright5018df72014-10-08 17:46:09 -0700364 if (mPrepared) {
Michael Lentined73854d2015-09-25 10:55:26 -0700365 dismissResources();
Michael Wright5018df72014-10-08 17:46:09 -0700366 destroySurface();
Michael Wright5018df72014-10-08 17:46:09 -0700367 mPrepared = false;
368 }
Jeff Brown96307042012-07-27 15:51:34 -0700369 }
370
371 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700372 * Draws an animation frame showing the color fade activated at the
Jeff Brown96307042012-07-27 15:51:34 -0700373 * specified level.
374 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700375 * @param level The color fade level.
Jeff Brown96307042012-07-27 15:51:34 -0700376 * @return True if successful.
377 */
378 public boolean draw(float level) {
379 if (DEBUG) {
380 Slog.d(TAG, "drawFrame: level=" + level);
381 }
382
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700383 if (!mPrepared) {
384 return false;
385 }
386
Jeff Brown252c2062012-10-08 16:21:01 -0700387 if (mMode == MODE_FADE) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700388 return showSurface(1.0f - level);
389 }
390
Jeff Brown96307042012-07-27 15:51:34 -0700391 if (!attachEglContext()) {
392 return false;
393 }
394 try {
395 // Clear frame to solid black.
Michael Lentine0839adb2014-07-29 18:47:56 -0700396 GLES20.glClearColor(0f, 0f, 0f, 1f);
397 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Jeff Brown96307042012-07-27 15:51:34 -0700398
399 // Draw the frame.
Neil Fullere573aa92015-02-11 15:49:47 +0000400 double one_minus_level = 1 - level;
401 double cos = Math.cos(Math.PI * one_minus_level);
402 double sign = cos < 0 ? -1 : 1;
403 float opacity = (float) -Math.pow(one_minus_level, 2) + 1;
Neil Fullere573aa92015-02-11 15:49:47 +0000404 float gamma = (float) ((0.5d * sign * Math.pow(cos, 2) + 0.5d) * 0.9d + 0.1d);
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800405 drawFaded(opacity, 1.f / gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700406 if (checkGlErrors("drawFrame")) {
407 return false;
408 }
409
410 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
411 } finally {
412 detachEglContext();
413 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700414 return showSurface(1.0f);
Jeff Brown96307042012-07-27 15:51:34 -0700415 }
416
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800417 private void drawFaded(float opacity, float gamma) {
Jeff Brown96307042012-07-27 15:51:34 -0700418 if (DEBUG) {
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800419 Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700420 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700421 // Use shaders
422 GLES20.glUseProgram(mProgram);
Jeff Brown96307042012-07-27 15:51:34 -0700423
Michael Lentine0839adb2014-07-29 18:47:56 -0700424 // Set Uniforms
425 GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0);
426 GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
427 GLES20.glUniform1f(mOpacityLoc, opacity);
428 GLES20.glUniform1f(mGammaLoc, gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700429
Michael Lentine0839adb2014-07-29 18:47:56 -0700430 // Use textures
431 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
432 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
Jeff Brown96307042012-07-27 15:51:34 -0700433
Michael Lentine0839adb2014-07-29 18:47:56 -0700434 // draw the plane
435 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
436 GLES20.glEnableVertexAttribArray(mVertexLoc);
437 GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800438
Michael Lentine0839adb2014-07-29 18:47:56 -0700439 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
440 GLES20.glEnableVertexAttribArray(mTexCoordLoc);
441 GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700442
Michael Lentine0839adb2014-07-29 18:47:56 -0700443 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
Jeff Brown96307042012-07-27 15:51:34 -0700444
445 // clean up
Michael Lentine0839adb2014-07-29 18:47:56 -0700446 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
447 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700448 }
449
Michael Lentine0839adb2014-07-29 18:47:56 -0700450 private void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
451 mProjMatrix[0] = 2f / (right - left);
452 mProjMatrix[1] = 0;
453 mProjMatrix[2] = 0;
454 mProjMatrix[3] = 0;
455 mProjMatrix[4] = 0;
456 mProjMatrix[5] = 2f / (top - bottom);
457 mProjMatrix[6] = 0;
458 mProjMatrix[7] = 0;
459 mProjMatrix[8] = 0;
460 mProjMatrix[9] = 0;
461 mProjMatrix[10] = -2f / (zfar - znear);
462 mProjMatrix[11] = 0;
463 mProjMatrix[12] = -(right + left) / (right - left);
464 mProjMatrix[13] = -(top + bottom) / (top - bottom);
465 mProjMatrix[14] = -(zfar + znear) / (zfar - znear);
466 mProjMatrix[15] = 1f;
Jeff Brown96307042012-07-27 15:51:34 -0700467 }
468
469 private boolean captureScreenshotTextureAndSetViewport() {
Mathias Agopian0449a402013-03-01 23:01:51 -0800470 if (!attachEglContext()) {
Jeff Brown96307042012-07-27 15:51:34 -0700471 return false;
472 }
473 try {
Mathias Agopian0449a402013-03-01 23:01:51 -0800474 if (!mTexNamesGenerated) {
Michael Lentine0839adb2014-07-29 18:47:56 -0700475 GLES20.glGenTextures(1, mTexNames, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800476 if (checkGlErrors("glGenTextures")) {
Jeff Brown96307042012-07-27 15:51:34 -0700477 return false;
478 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800479 mTexNamesGenerated = true;
Jeff Brown96307042012-07-27 15:51:34 -0700480 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800481
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700482 final SurfaceTexture st = new SurfaceTexture(mTexNames[0]);
483 final Surface s = new Surface(st);
484 try {
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800485 final IBinder token = SurfaceControl.getInternalDisplayToken();
486 if (token == null) {
487 Slog.e(TAG,
488 "Failed to take screenshot because internal display is disconnected");
489 return false;
490 }
491
Peiyong Lin8f6d2782019-07-17 16:05:10 -0700492 mIsWideColor = SurfaceControl.getActiveColorMode(token)
493 == Display.COLOR_MODE_DISPLAY_P3;
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800494 SurfaceControl.screenshot(token, s);
Michael Wright2ed05132015-01-08 14:30:47 -0800495 st.updateTexImage();
496 st.getTransformMatrix(mTexMatrix);
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700497 } finally {
498 s.release();
Michael Wright2ed05132015-01-08 14:30:47 -0800499 st.release();
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700500 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800501
Mathias Agopian0449a402013-03-01 23:01:51 -0800502 // Set up texture coordinates for a quad.
503 // We might need to change this if the texture ends up being
504 // a different size from the display for some reason.
505 mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f);
506 mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f);
507 mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f);
508 mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
509
510 // Set up our viewport.
Michael Lentine0839adb2014-07-29 18:47:56 -0700511 GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
512 ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1);
Jeff Brown96307042012-07-27 15:51:34 -0700513 } finally {
Mathias Agopian0449a402013-03-01 23:01:51 -0800514 detachEglContext();
Jeff Brown96307042012-07-27 15:51:34 -0700515 }
516 return true;
517 }
518
519 private void destroyScreenshotTexture() {
520 if (mTexNamesGenerated) {
521 mTexNamesGenerated = false;
Michael Wright5018df72014-10-08 17:46:09 -0700522 GLES20.glDeleteTextures(1, mTexNames, 0);
523 checkGlErrors("glDeleteTextures");
Jeff Brown96307042012-07-27 15:51:34 -0700524 }
525 }
526
527 private boolean createEglContext() {
528 if (mEglDisplay == null) {
529 mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
530 if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
531 logEglError("eglGetDisplay");
532 return false;
533 }
534
535 int[] version = new int[2];
536 if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
537 mEglDisplay = null;
538 logEglError("eglInitialize");
539 return false;
540 }
541 }
542
543 if (mEglConfig == null) {
544 int[] eglConfigAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700545 EGL14.EGL_RENDERABLE_TYPE,
546 EGL14.EGL_OPENGL_ES2_BIT,
Jeff Brown96307042012-07-27 15:51:34 -0700547 EGL14.EGL_RED_SIZE, 8,
548 EGL14.EGL_GREEN_SIZE, 8,
549 EGL14.EGL_BLUE_SIZE, 8,
550 EGL14.EGL_ALPHA_SIZE, 8,
551 EGL14.EGL_NONE
552 };
553 int[] numEglConfigs = new int[1];
554 EGLConfig[] eglConfigs = new EGLConfig[1];
555 if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0,
556 eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) {
557 logEglError("eglChooseConfig");
558 return false;
559 }
Ivan.liu984827c2016-08-24 17:19:03 +0800560 if (numEglConfigs[0] <= 0) {
561 Slog.e(TAG, "no valid config found");
562 return false;
563 }
564
Jeff Brown96307042012-07-27 15:51:34 -0700565 mEglConfig = eglConfigs[0];
566 }
567
568 if (mEglContext == null) {
569 int[] eglContextAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700570 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
Jeff Brown96307042012-07-27 15:51:34 -0700571 EGL14.EGL_NONE
572 };
573 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
574 EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
575 if (mEglContext == null) {
576 logEglError("eglCreateContext");
577 return false;
578 }
579 }
580 return true;
581 }
582
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700583 private boolean createSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700584 if (mSurfaceSession == null) {
585 mSurfaceSession = new SurfaceSession();
586 }
587
Vishnu Naire86bd982018-11-28 13:23:17 -0800588 if (mSurfaceControl == null) {
589 Transaction t = new Transaction();
590 try {
Jorim Jaggid42ab1b2020-06-19 00:49:51 +0200591 final SurfaceControl.Builder builder = new SurfaceControl.Builder(mSurfaceSession)
592 .setName("ColorFade")
593 .setCallsite("ColorFade.createSurface");
Vishnu Naire86bd982018-11-28 13:23:17 -0800594 if (mMode == MODE_FADE) {
Chavi Weingarten6ef9cc62019-02-07 16:28:45 +0000595 builder.setColorLayer();
Vishnu Naire86bd982018-11-28 13:23:17 -0800596 } else {
597 builder.setBufferSize(mDisplayWidth, mDisplayHeight);
Jeff Brown96307042012-07-27 15:51:34 -0700598 }
Vishnu Naire86bd982018-11-28 13:23:17 -0800599 mSurfaceControl = builder.build();
600 } catch (OutOfResourcesException ex) {
601 Slog.e(TAG, "Unable to create surface.", ex);
602 return false;
Jeff Brown96307042012-07-27 15:51:34 -0700603 }
Vishnu Naire86bd982018-11-28 13:23:17 -0800604
605 t.setLayerStack(mSurfaceControl, mDisplayLayerStack);
606 t.setWindowCrop(mSurfaceControl, mDisplayWidth, mDisplayHeight);
607 mSurface = new Surface();
608 mSurface.copyFrom(mSurfaceControl);
609
610 mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
611 mDisplayId, mSurfaceControl);
612 mSurfaceLayout.onDisplayTransaction(t);
613 t.apply();
Jeff Brown96307042012-07-27 15:51:34 -0700614 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700615 return true;
616 }
Jeff Brown96307042012-07-27 15:51:34 -0700617
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700618 private boolean createEglSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700619 if (mEglSurface == null) {
620 int[] eglSurfaceAttribList = new int[] {
Peiyong Lin8f6d2782019-07-17 16:05:10 -0700621 EGL14.EGL_NONE,
622 EGL14.EGL_NONE,
Jeff Brown96307042012-07-27 15:51:34 -0700623 EGL14.EGL_NONE
624 };
Peiyong Lin8f6d2782019-07-17 16:05:10 -0700625
626 // If the current display is in wide color, then so is the screenshot.
627 if (mIsWideColor) {
628 eglSurfaceAttribList[0] = EGL_GL_COLORSPACE_KHR;
629 eglSurfaceAttribList[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
630 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800631 // turn our SurfaceControl into a Surface
Jeff Brown96307042012-07-27 15:51:34 -0700632 mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
633 eglSurfaceAttribList, 0);
634 if (mEglSurface == null) {
635 logEglError("eglCreateWindowSurface");
636 return false;
637 }
638 }
639 return true;
640 }
641
642 private void destroyEglSurface() {
643 if (mEglSurface != null) {
644 if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) {
645 logEglError("eglDestroySurface");
646 }
647 mEglSurface = null;
648 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700649 }
Jeff Brown96307042012-07-27 15:51:34 -0700650
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700651 private void destroySurface() {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800652 if (mSurfaceControl != null) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800653 mSurfaceLayout.dispose();
654 mSurfaceLayout = null;
chaviw9f6171e2019-06-07 16:33:50 -0700655 new Transaction().remove(mSurfaceControl).apply();
656 mSurface.release();
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800657 mSurfaceControl = null;
Jeff Brown96307042012-07-27 15:51:34 -0700658 mSurfaceVisible = false;
Jeff Brown252c2062012-10-08 16:21:01 -0700659 mSurfaceAlpha = 0f;
Jeff Brown96307042012-07-27 15:51:34 -0700660 }
661 }
662
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700663 private boolean showSurface(float alpha) {
Jeff Brown252c2062012-10-08 16:21:01 -0700664 if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
chaviw619da692019-06-10 15:39:40 -0700665 mTransaction.setLayer(mSurfaceControl, COLOR_FADE_LAYER)
666 .setAlpha(mSurfaceControl, alpha)
667 .show(mSurfaceControl)
668 .apply();
Jeff Brown96307042012-07-27 15:51:34 -0700669 mSurfaceVisible = true;
Jeff Brown252c2062012-10-08 16:21:01 -0700670 mSurfaceAlpha = alpha;
Jeff Brown96307042012-07-27 15:51:34 -0700671 }
672 return true;
673 }
674
675 private boolean attachEglContext() {
676 if (mEglSurface == null) {
677 return false;
678 }
679 if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
680 logEglError("eglMakeCurrent");
681 return false;
682 }
683 return true;
684 }
685
686 private void detachEglContext() {
687 if (mEglDisplay != null) {
688 EGL14.eglMakeCurrent(mEglDisplay,
689 EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
690 }
691 }
692
Jeff Brown96307042012-07-27 15:51:34 -0700693 private static FloatBuffer createNativeFloatBuffer(int size) {
694 ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
695 bb.order(ByteOrder.nativeOrder());
696 return bb.asFloatBuffer();
697 }
698
699 private static void logEglError(String func) {
700 Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable());
701 }
702
703 private static boolean checkGlErrors(String func) {
704 return checkGlErrors(func, true);
705 }
706
707 private static boolean checkGlErrors(String func, boolean log) {
708 boolean hadError = false;
709 int error;
Michael Lentine0839adb2014-07-29 18:47:56 -0700710 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Jeff Brown96307042012-07-27 15:51:34 -0700711 if (log) {
712 Slog.e(TAG, func + " failed: error " + error, new Throwable());
713 }
714 hadError = true;
715 }
716 return hadError;
717 }
718
719 public void dump(PrintWriter pw) {
720 pw.println();
Michael Lentine0839adb2014-07-29 18:47:56 -0700721 pw.println("Color Fade State:");
Jeff Brown96307042012-07-27 15:51:34 -0700722 pw.println(" mPrepared=" + mPrepared);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700723 pw.println(" mMode=" + mMode);
Jeff Brown96307042012-07-27 15:51:34 -0700724 pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
Jeff Brown96307042012-07-27 15:51:34 -0700725 pw.println(" mDisplayWidth=" + mDisplayWidth);
726 pw.println(" mDisplayHeight=" + mDisplayHeight);
727 pw.println(" mSurfaceVisible=" + mSurfaceVisible);
Jeff Brown252c2062012-10-08 16:21:01 -0700728 pw.println(" mSurfaceAlpha=" + mSurfaceAlpha);
Jeff Brown96307042012-07-27 15:51:34 -0700729 }
Jeff Brown7f3994e2012-12-04 14:04:28 -0800730
731 /**
732 * Keeps a surface aligned with the natural orientation of the device.
733 * Updates the position and transformation of the matrix whenever the display
734 * is rotated. This is a little tricky because the display transaction
735 * callback can be invoked on any thread, not necessarily the thread that
Michael Lentine0839adb2014-07-29 18:47:56 -0700736 * owns the color fade.
Jeff Brown7f3994e2012-12-04 14:04:28 -0800737 */
738 private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
Jeff Brown4ccb8232014-01-16 22:16:42 -0800739 private final DisplayManagerInternal mDisplayManagerInternal;
Jeff Brown037c33e2014-04-09 00:31:55 -0700740 private final int mDisplayId;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800741 private SurfaceControl mSurfaceControl;
Jeff Brown7f3994e2012-12-04 14:04:28 -0800742
Jeff Brown4ccb8232014-01-16 22:16:42 -0800743 public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
Jeff Brown037c33e2014-04-09 00:31:55 -0700744 int displayId, SurfaceControl surfaceControl) {
Jeff Brown4ccb8232014-01-16 22:16:42 -0800745 mDisplayManagerInternal = displayManagerInternal;
Jeff Brown037c33e2014-04-09 00:31:55 -0700746 mDisplayId = displayId;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800747 mSurfaceControl = surfaceControl;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800748 mDisplayManagerInternal.registerDisplayTransactionListener(this);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800749 }
750
751 public void dispose() {
752 synchronized (this) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800753 mSurfaceControl = null;
Jeff Brown7f3994e2012-12-04 14:04:28 -0800754 }
Jeff Brown4ccb8232014-01-16 22:16:42 -0800755 mDisplayManagerInternal.unregisterDisplayTransactionListener(this);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800756 }
757
758 @Override
Vishnu Naire86bd982018-11-28 13:23:17 -0800759 public void onDisplayTransaction(Transaction t) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800760 synchronized (this) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800761 if (mSurfaceControl == null) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800762 return;
763 }
764
Jeff Brown037c33e2014-04-09 00:31:55 -0700765 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800766 switch (displayInfo.rotation) {
767 case Surface.ROTATION_0:
Vishnu Naire86bd982018-11-28 13:23:17 -0800768 t.setPosition(mSurfaceControl, 0, 0);
769 t.setMatrix(mSurfaceControl, 1, 0, 0, 1);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800770 break;
771 case Surface.ROTATION_90:
Vishnu Naire86bd982018-11-28 13:23:17 -0800772 t.setPosition(mSurfaceControl, 0, displayInfo.logicalHeight);
773 t.setMatrix(mSurfaceControl, 0, -1, 1, 0);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800774 break;
775 case Surface.ROTATION_180:
Vishnu Naire86bd982018-11-28 13:23:17 -0800776 t.setPosition(mSurfaceControl, displayInfo.logicalWidth,
Michael Lentine0839adb2014-07-29 18:47:56 -0700777 displayInfo.logicalHeight);
Vishnu Naire86bd982018-11-28 13:23:17 -0800778 t.setMatrix(mSurfaceControl, -1, 0, 0, -1);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800779 break;
780 case Surface.ROTATION_270:
Vishnu Naire86bd982018-11-28 13:23:17 -0800781 t.setPosition(mSurfaceControl, displayInfo.logicalWidth, 0);
782 t.setMatrix(mSurfaceControl, 0, 1, -1, 0);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800783 break;
784 }
785 }
786 }
787 }
Jeff Brown96307042012-07-27 15:51:34 -0700788}