blob: 4f53ed49002b895bf4bf20586dfda746cf4a7ab0 [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;
Jeff Brown96307042012-07-27 15:51:34 -070049
50/**
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070051 * <p>
Jeff Brown96307042012-07-27 15:51:34 -070052 * Animates a screen transition from on to off or off to on by applying
53 * some GL transformations to a screenshot.
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070054 * </p><p>
Jeff Brown96307042012-07-27 15:51:34 -070055 * This component must only be created or accessed by the {@link Looper} thread
56 * that belongs to the {@link DisplayPowerController}.
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070057 * </p>
Jeff Brown96307042012-07-27 15:51:34 -070058 */
Michael Lentine0839adb2014-07-29 18:47:56 -070059final class ColorFade {
60 private static final String TAG = "ColorFade";
Jeff Brown96307042012-07-27 15:51:34 -070061
62 private static final boolean DEBUG = false;
63
64 // The layer for the electron beam surface.
65 // This is currently hardcoded to be one layer above the boot animation.
Michael Lentine0839adb2014-07-29 18:47:56 -070066 private static final int COLOR_FADE_LAYER = 0x40000001;
Jeff Brown96307042012-07-27 15:51:34 -070067
Jeff Brown78eb1222012-10-10 18:27:44 -070068 // The number of frames to draw when preparing the animation so that it will
69 // be ready to run smoothly. We use 3 frames because we are triple-buffered.
70 // See code for details.
71 private static final int DEJANK_FRAMES = 3;
72
Jeff Brown037c33e2014-04-09 00:31:55 -070073 private final int mDisplayId;
74
Jeff Brown96307042012-07-27 15:51:34 -070075 // Set to true when the animation context has been fully prepared.
76 private boolean mPrepared;
Michael Lentined73854d2015-09-25 10:55:26 -070077 private boolean mCreatedResources;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070078 private int mMode;
Jeff Brown96307042012-07-27 15:51:34 -070079
Jeff Brown4ccb8232014-01-16 22:16:42 -080080 private final DisplayManagerInternal mDisplayManagerInternal;
Jeff Brown96307042012-07-27 15:51:34 -070081 private int mDisplayLayerStack; // layer stack associated with primary display
Jeff Brown96307042012-07-27 15:51:34 -070082 private int mDisplayWidth; // real width, not rotated
83 private int mDisplayHeight; // real height, not rotated
84 private SurfaceSession mSurfaceSession;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080085 private SurfaceControl mSurfaceControl;
Mathias Agopian86e1bc72013-03-13 17:48:22 -070086 private Surface mSurface;
Jeff Brown7f3994e2012-12-04 14:04:28 -080087 private NaturalSurfaceLayout mSurfaceLayout;
Jeff Brown96307042012-07-27 15:51:34 -070088 private EGLDisplay mEglDisplay;
89 private EGLConfig mEglConfig;
90 private EGLContext mEglContext;
91 private EGLSurface mEglSurface;
92 private boolean mSurfaceVisible;
Jeff Brown252c2062012-10-08 16:21:01 -070093 private float mSurfaceAlpha;
Jeff Brown96307042012-07-27 15:51:34 -070094
95 // Texture names. We only use one texture, which contains the screenshot.
96 private final int[] mTexNames = new int[1];
97 private boolean mTexNamesGenerated;
Igor Murashkina86ab6402013-08-30 12:58:36 -070098 private final float mTexMatrix[] = new float[16];
Michael Lentine0839adb2014-07-29 18:47:56 -070099 private final float mProjMatrix[] = new float[16];
100 private final int[] mGLBuffers = new int[2];
101 private int mTexCoordLoc, mVertexLoc, mTexUnitLoc, mProjMatrixLoc, mTexMatrixLoc;
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800102 private int mOpacityLoc, mGammaLoc;
Michael Lentine0839adb2014-07-29 18:47:56 -0700103 private int mProgram;
Jeff Brown96307042012-07-27 15:51:34 -0700104
105 // Vertex and corresponding texture coordinates.
106 // We have 4 2D vertices, so 8 elements. The vertices form a quad.
107 private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
108 private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
109
Jeff Brown252c2062012-10-08 16:21:01 -0700110 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700111 * Animates an color fade warming up.
Jeff Brown252c2062012-10-08 16:21:01 -0700112 */
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700113 public static final int MODE_WARM_UP = 0;
Jeff Brown252c2062012-10-08 16:21:01 -0700114
115 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700116 * Animates an color fade shutting off.
Jeff Brown252c2062012-10-08 16:21:01 -0700117 */
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700118 public static final int MODE_COOL_DOWN = 1;
Jeff Brown252c2062012-10-08 16:21:01 -0700119
120 /**
121 * Animates a simple dim layer to fade the contents of the screen in or out progressively.
122 */
123 public static final int MODE_FADE = 2;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700124
Michael Lentine0839adb2014-07-29 18:47:56 -0700125 public ColorFade(int displayId) {
Jeff Brown037c33e2014-04-09 00:31:55 -0700126 mDisplayId = displayId;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800127 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
Jeff Brown96307042012-07-27 15:51:34 -0700128 }
129
130 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700131 * Warms up the color fade in preparation for turning on or off.
Jeff Brown96307042012-07-27 15:51:34 -0700132 * This method prepares a GL context, and captures a screen shot.
133 *
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700134 * @param mode The desired mode for the upcoming animation.
Michael Lentine0839adb2014-07-29 18:47:56 -0700135 * @return True if the color fade is ready, false if it is uncontrollable.
Jeff Brown96307042012-07-27 15:51:34 -0700136 */
Michael Lentine0839adb2014-07-29 18:47:56 -0700137 public boolean prepare(Context context, int mode) {
Jeff Brown96307042012-07-27 15:51:34 -0700138 if (DEBUG) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700139 Slog.d(TAG, "prepare: mode=" + mode);
Jeff Brown96307042012-07-27 15:51:34 -0700140 }
141
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700142 mMode = mode;
Jeff Brown96307042012-07-27 15:51:34 -0700143
Jeff Brown7f3994e2012-12-04 14:04:28 -0800144 // Get the display size and layer stack.
Michael Lentine0839adb2014-07-29 18:47:56 -0700145 // This is not expected to change while the color fade surface is showing.
Jeff Brown037c33e2014-04-09 00:31:55 -0700146 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800147 mDisplayLayerStack = displayInfo.layerStack;
148 mDisplayWidth = displayInfo.getNaturalWidth();
149 mDisplayHeight = displayInfo.getNaturalHeight();
Jeff Brown96307042012-07-27 15:51:34 -0700150
151 // Prepare the surface for drawing.
Michael Lentine0839adb2014-07-29 18:47:56 -0700152 if (!(createSurface() && createEglContext() && createEglSurface() &&
153 captureScreenshotTextureAndSetViewport())) {
Jeff Brown96307042012-07-27 15:51:34 -0700154 dismiss();
155 return false;
156 }
157
Michael Lentine0839adb2014-07-29 18:47:56 -0700158 // Init GL
159 if (!attachEglContext()) {
160 return false;
161 }
162 try {
163 if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
164 detachEglContext();
165 dismiss();
166 return false;
167 }
168 } finally {
169 detachEglContext();
170 }
171
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700172 // Done.
Michael Lentined73854d2015-09-25 10:55:26 -0700173 mCreatedResources = true;
Jeff Brown96307042012-07-27 15:51:34 -0700174 mPrepared = true;
Jeff Brown78eb1222012-10-10 18:27:44 -0700175
176 // Dejanking optimization.
177 // Some GL drivers can introduce a lot of lag in the first few frames as they
178 // initialize their state and allocate graphics buffers for rendering.
179 // Work around this problem by rendering the first frame of the animation a few
180 // times. The rest of the animation should run smoothly thereafter.
181 // The frames we draw here aren't visible because we are essentially just
182 // painting the screenshot as-is.
183 if (mode == MODE_COOL_DOWN) {
184 for (int i = 0; i < DEJANK_FRAMES; i++) {
185 draw(1.0f);
186 }
187 }
Jeff Brown96307042012-07-27 15:51:34 -0700188 return true;
189 }
190
Michael Lentine0839adb2014-07-29 18:47:56 -0700191 private String readFile(Context context, int resourceId) {
192 try{
193 InputStream stream = context.getResources().openRawResource(resourceId);
194 return new String(Streams.readFully(new InputStreamReader(stream)));
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700195 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700196 catch (IOException e) {
197 Slog.e(TAG, "Unrecognized shader " + Integer.toString(resourceId));
198 throw new RuntimeException(e);
199 }
200 }
201
202 private int loadShader(Context context, int resourceId, int type) {
203 String source = readFile(context, resourceId);
204
205 int shader = GLES20.glCreateShader(type);
206
207 GLES20.glShaderSource(shader, source);
208 GLES20.glCompileShader(shader);
209
210 int[] compiled = new int[1];
211 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
212 if (compiled[0] == 0) {
213 Slog.e(TAG, "Could not compile shader " + shader + ", " + type + ":");
214 Slog.e(TAG, GLES20.glGetShaderSource(shader));
215 Slog.e(TAG, GLES20.glGetShaderInfoLog(shader));
216 GLES20.glDeleteShader(shader);
217 shader = 0;
218 }
219
220 return shader;
221 }
222
223 private boolean initGLShaders(Context context) {
224 int vshader = loadShader(context, com.android.internal.R.raw.color_fade_vert,
225 GLES20.GL_VERTEX_SHADER);
226 int fshader = loadShader(context, com.android.internal.R.raw.color_fade_frag,
227 GLES20.GL_FRAGMENT_SHADER);
Michael Wright5018df72014-10-08 17:46:09 -0700228 GLES20.glReleaseShaderCompiler();
Michael Lentine0839adb2014-07-29 18:47:56 -0700229 if (vshader == 0 || fshader == 0) return false;
230
231 mProgram = GLES20.glCreateProgram();
232
233 GLES20.glAttachShader(mProgram, vshader);
234 GLES20.glAttachShader(mProgram, fshader);
Michael Wright5018df72014-10-08 17:46:09 -0700235 GLES20.glDeleteShader(vshader);
236 GLES20.glDeleteShader(fshader);
Michael Lentine0839adb2014-07-29 18:47:56 -0700237
238 GLES20.glLinkProgram(mProgram);
239
240 mVertexLoc = GLES20.glGetAttribLocation(mProgram, "position");
241 mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "uv");
242
243 mProjMatrixLoc = GLES20.glGetUniformLocation(mProgram, "proj_matrix");
244 mTexMatrixLoc = GLES20.glGetUniformLocation(mProgram, "tex_matrix");
245
246 mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity");
247 mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma");
Michael Lentine0839adb2014-07-29 18:47:56 -0700248 mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit");
249
250 GLES20.glUseProgram(mProgram);
251 GLES20.glUniform1i(mTexUnitLoc, 0);
252 GLES20.glUseProgram(0);
253
254 return true;
255 }
256
Michael Wright5018df72014-10-08 17:46:09 -0700257 private void destroyGLShaders() {
258 GLES20.glDeleteProgram(mProgram);
259 checkGlErrors("glDeleteProgram");
260 }
261
Michael Lentine0839adb2014-07-29 18:47:56 -0700262 private boolean initGLBuffers() {
263 //Fill vertices
264 setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight);
265
266 // Setup GL Textures
267 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
268 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
269 GLES20.GL_NEAREST);
270 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
271 GLES20.GL_NEAREST);
272 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
273 GLES20.GL_CLAMP_TO_EDGE);
274 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
275 GLES20.GL_CLAMP_TO_EDGE);
276 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
277
278 // Setup GL Buffers
279 GLES20.glGenBuffers(2, mGLBuffers, 0);
280
281 // fill vertex buffer
282 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
283 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4,
284 mVertexBuffer, GLES20.GL_STATIC_DRAW);
285
286 // fill tex buffer
287 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
288 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4,
289 mTexCoordBuffer, GLES20.GL_STATIC_DRAW);
290
291 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
292
293 return true;
294 }
295
Michael Wright5018df72014-10-08 17:46:09 -0700296 private void destroyGLBuffers() {
297 GLES20.glDeleteBuffers(2, mGLBuffers, 0);
298 checkGlErrors("glDeleteBuffers");
299 }
300
Michael Lentine0839adb2014-07-29 18:47:56 -0700301 private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
302 if (DEBUG) {
303 Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
304 }
305 vtx.put(0, x);
306 vtx.put(1, y);
307 vtx.put(2, x);
308 vtx.put(3, y + h);
309 vtx.put(4, x + w);
310 vtx.put(5, y + h);
311 vtx.put(6, x + w);
312 vtx.put(7, y);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700313 }
314
Jeff Brown96307042012-07-27 15:51:34 -0700315 /**
Michael Lentined73854d2015-09-25 10:55:26 -0700316 * Dismisses the color fade animation resources.
317 *
318 * This function destroys the resources that are created for the color fade
319 * animation but does not clean up the surface.
320 */
321 public void dismissResources() {
322 if (DEBUG) {
323 Slog.d(TAG, "dismissResources");
324 }
325
326 if (mCreatedResources) {
327 attachEglContext();
328 try {
329 destroyScreenshotTexture();
330 destroyGLShaders();
331 destroyGLBuffers();
332 destroyEglSurface();
333 } finally {
334 detachEglContext();
335 }
336 // This is being called with no active context so shouldn't be
337 // needed but is safer to not change for now.
338 GLES20.glFlush();
339 mCreatedResources = false;
340 }
341 }
342
343 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700344 * Dismisses the color fade animation surface and cleans up.
Jeff Brown96307042012-07-27 15:51:34 -0700345 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700346 * To prevent stray photons from leaking out after the color fade has been
Jeff Brown96307042012-07-27 15:51:34 -0700347 * turned off, it is a good idea to defer dismissing the animation until the
Michael Lentine0839adb2014-07-29 18:47:56 -0700348 * color fade has been turned back on fully.
Jeff Brown96307042012-07-27 15:51:34 -0700349 */
350 public void dismiss() {
351 if (DEBUG) {
352 Slog.d(TAG, "dismiss");
353 }
354
Michael Wright5018df72014-10-08 17:46:09 -0700355 if (mPrepared) {
Michael Lentined73854d2015-09-25 10:55:26 -0700356 dismissResources();
Michael Wright5018df72014-10-08 17:46:09 -0700357 destroySurface();
Michael Wright5018df72014-10-08 17:46:09 -0700358 mPrepared = false;
359 }
Jeff Brown96307042012-07-27 15:51:34 -0700360 }
361
362 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700363 * Draws an animation frame showing the color fade activated at the
Jeff Brown96307042012-07-27 15:51:34 -0700364 * specified level.
365 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700366 * @param level The color fade level.
Jeff Brown96307042012-07-27 15:51:34 -0700367 * @return True if successful.
368 */
369 public boolean draw(float level) {
370 if (DEBUG) {
371 Slog.d(TAG, "drawFrame: level=" + level);
372 }
373
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700374 if (!mPrepared) {
375 return false;
376 }
377
Jeff Brown252c2062012-10-08 16:21:01 -0700378 if (mMode == MODE_FADE) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700379 return showSurface(1.0f - level);
380 }
381
Jeff Brown96307042012-07-27 15:51:34 -0700382 if (!attachEglContext()) {
383 return false;
384 }
385 try {
386 // Clear frame to solid black.
Michael Lentine0839adb2014-07-29 18:47:56 -0700387 GLES20.glClearColor(0f, 0f, 0f, 1f);
388 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Jeff Brown96307042012-07-27 15:51:34 -0700389
390 // Draw the frame.
Neil Fullere573aa92015-02-11 15:49:47 +0000391 double one_minus_level = 1 - level;
392 double cos = Math.cos(Math.PI * one_minus_level);
393 double sign = cos < 0 ? -1 : 1;
394 float opacity = (float) -Math.pow(one_minus_level, 2) + 1;
Neil Fullere573aa92015-02-11 15:49:47 +0000395 float gamma = (float) ((0.5d * sign * Math.pow(cos, 2) + 0.5d) * 0.9d + 0.1d);
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800396 drawFaded(opacity, 1.f / gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700397 if (checkGlErrors("drawFrame")) {
398 return false;
399 }
400
401 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
402 } finally {
403 detachEglContext();
404 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700405 return showSurface(1.0f);
Jeff Brown96307042012-07-27 15:51:34 -0700406 }
407
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800408 private void drawFaded(float opacity, float gamma) {
Jeff Brown96307042012-07-27 15:51:34 -0700409 if (DEBUG) {
Lucas Dupin9559d7a2018-01-15 09:31:42 -0800410 Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700411 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700412 // Use shaders
413 GLES20.glUseProgram(mProgram);
Jeff Brown96307042012-07-27 15:51:34 -0700414
Michael Lentine0839adb2014-07-29 18:47:56 -0700415 // Set Uniforms
416 GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0);
417 GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
418 GLES20.glUniform1f(mOpacityLoc, opacity);
419 GLES20.glUniform1f(mGammaLoc, gamma);
Jeff Brown96307042012-07-27 15:51:34 -0700420
Michael Lentine0839adb2014-07-29 18:47:56 -0700421 // Use textures
422 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
423 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
Jeff Brown96307042012-07-27 15:51:34 -0700424
Michael Lentine0839adb2014-07-29 18:47:56 -0700425 // draw the plane
426 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
427 GLES20.glEnableVertexAttribArray(mVertexLoc);
428 GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800429
Michael Lentine0839adb2014-07-29 18:47:56 -0700430 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
431 GLES20.glEnableVertexAttribArray(mTexCoordLoc);
432 GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700433
Michael Lentine0839adb2014-07-29 18:47:56 -0700434 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
Jeff Brown96307042012-07-27 15:51:34 -0700435
436 // clean up
Michael Lentine0839adb2014-07-29 18:47:56 -0700437 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
438 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700439 }
440
Michael Lentine0839adb2014-07-29 18:47:56 -0700441 private void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
442 mProjMatrix[0] = 2f / (right - left);
443 mProjMatrix[1] = 0;
444 mProjMatrix[2] = 0;
445 mProjMatrix[3] = 0;
446 mProjMatrix[4] = 0;
447 mProjMatrix[5] = 2f / (top - bottom);
448 mProjMatrix[6] = 0;
449 mProjMatrix[7] = 0;
450 mProjMatrix[8] = 0;
451 mProjMatrix[9] = 0;
452 mProjMatrix[10] = -2f / (zfar - znear);
453 mProjMatrix[11] = 0;
454 mProjMatrix[12] = -(right + left) / (right - left);
455 mProjMatrix[13] = -(top + bottom) / (top - bottom);
456 mProjMatrix[14] = -(zfar + znear) / (zfar - znear);
457 mProjMatrix[15] = 1f;
Jeff Brown96307042012-07-27 15:51:34 -0700458 }
459
460 private boolean captureScreenshotTextureAndSetViewport() {
Mathias Agopian0449a402013-03-01 23:01:51 -0800461 if (!attachEglContext()) {
Jeff Brown96307042012-07-27 15:51:34 -0700462 return false;
463 }
464 try {
Mathias Agopian0449a402013-03-01 23:01:51 -0800465 if (!mTexNamesGenerated) {
Michael Lentine0839adb2014-07-29 18:47:56 -0700466 GLES20.glGenTextures(1, mTexNames, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800467 if (checkGlErrors("glGenTextures")) {
Jeff Brown96307042012-07-27 15:51:34 -0700468 return false;
469 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800470 mTexNamesGenerated = true;
Jeff Brown96307042012-07-27 15:51:34 -0700471 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800472
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700473 final SurfaceTexture st = new SurfaceTexture(mTexNames[0]);
474 final Surface s = new Surface(st);
475 try {
476 SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
477 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), s);
Michael Wright2ed05132015-01-08 14:30:47 -0800478 st.updateTexImage();
479 st.getTransformMatrix(mTexMatrix);
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700480 } finally {
481 s.release();
Michael Wright2ed05132015-01-08 14:30:47 -0800482 st.release();
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700483 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800484
Mathias Agopian0449a402013-03-01 23:01:51 -0800485 // Set up texture coordinates for a quad.
486 // We might need to change this if the texture ends up being
487 // a different size from the display for some reason.
488 mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f);
489 mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f);
490 mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f);
491 mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
492
493 // Set up our viewport.
Michael Lentine0839adb2014-07-29 18:47:56 -0700494 GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
495 ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1);
Jeff Brown96307042012-07-27 15:51:34 -0700496 } finally {
Mathias Agopian0449a402013-03-01 23:01:51 -0800497 detachEglContext();
Jeff Brown96307042012-07-27 15:51:34 -0700498 }
499 return true;
500 }
501
502 private void destroyScreenshotTexture() {
503 if (mTexNamesGenerated) {
504 mTexNamesGenerated = false;
Michael Wright5018df72014-10-08 17:46:09 -0700505 GLES20.glDeleteTextures(1, mTexNames, 0);
506 checkGlErrors("glDeleteTextures");
Jeff Brown96307042012-07-27 15:51:34 -0700507 }
508 }
509
510 private boolean createEglContext() {
511 if (mEglDisplay == null) {
512 mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
513 if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
514 logEglError("eglGetDisplay");
515 return false;
516 }
517
518 int[] version = new int[2];
519 if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
520 mEglDisplay = null;
521 logEglError("eglInitialize");
522 return false;
523 }
524 }
525
526 if (mEglConfig == null) {
527 int[] eglConfigAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700528 EGL14.EGL_RENDERABLE_TYPE,
529 EGL14.EGL_OPENGL_ES2_BIT,
Jeff Brown96307042012-07-27 15:51:34 -0700530 EGL14.EGL_RED_SIZE, 8,
531 EGL14.EGL_GREEN_SIZE, 8,
532 EGL14.EGL_BLUE_SIZE, 8,
533 EGL14.EGL_ALPHA_SIZE, 8,
534 EGL14.EGL_NONE
535 };
536 int[] numEglConfigs = new int[1];
537 EGLConfig[] eglConfigs = new EGLConfig[1];
538 if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0,
539 eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) {
540 logEglError("eglChooseConfig");
541 return false;
542 }
Ivan.liu984827c2016-08-24 17:19:03 +0800543 if (numEglConfigs[0] <= 0) {
544 Slog.e(TAG, "no valid config found");
545 return false;
546 }
547
Jeff Brown96307042012-07-27 15:51:34 -0700548 mEglConfig = eglConfigs[0];
549 }
550
551 if (mEglContext == null) {
552 int[] eglContextAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700553 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
Jeff Brown96307042012-07-27 15:51:34 -0700554 EGL14.EGL_NONE
555 };
556 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
557 EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
558 if (mEglContext == null) {
559 logEglError("eglCreateContext");
560 return false;
561 }
562 }
563 return true;
564 }
565
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700566 private boolean createSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700567 if (mSurfaceSession == null) {
568 mSurfaceSession = new SurfaceSession();
569 }
570
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800571 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700572 try {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800573 if (mSurfaceControl == null) {
Jeff Brown96307042012-07-27 15:51:34 -0700574 try {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700575 int flags;
Jeff Brown252c2062012-10-08 16:21:01 -0700576 if (mMode == MODE_FADE) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800577 flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700578 } else {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800579 flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700580 }
Robert Carre625fcf2017-09-01 12:36:28 -0700581 mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
582 .setName("ColorFade")
583 .setSize(mDisplayWidth, mDisplayHeight)
584 .setFlags(flags)
585 .build();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700586 } catch (OutOfResourcesException ex) {
Jeff Brown96307042012-07-27 15:51:34 -0700587 Slog.e(TAG, "Unable to create surface.", ex);
588 return false;
589 }
yang.xa.liu40d73a72015-12-18 16:40:31 +0800590
591 mSurfaceControl.setLayerStack(mDisplayLayerStack);
592 mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
593 mSurface = new Surface();
594 mSurface.copyFrom(mSurfaceControl);
595
596 mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
597 mDisplayId, mSurfaceControl);
598 mSurfaceLayout.onDisplayTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700599 }
Jeff Brown96307042012-07-27 15:51:34 -0700600 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800601 SurfaceControl.closeTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700602 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700603 return true;
604 }
Jeff Brown96307042012-07-27 15:51:34 -0700605
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700606 private boolean createEglSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700607 if (mEglSurface == null) {
608 int[] eglSurfaceAttribList = new int[] {
609 EGL14.EGL_NONE
610 };
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800611 // turn our SurfaceControl into a Surface
Jeff Brown96307042012-07-27 15:51:34 -0700612 mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
613 eglSurfaceAttribList, 0);
614 if (mEglSurface == null) {
615 logEglError("eglCreateWindowSurface");
616 return false;
617 }
618 }
619 return true;
620 }
621
622 private void destroyEglSurface() {
623 if (mEglSurface != null) {
624 if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) {
625 logEglError("eglDestroySurface");
626 }
627 mEglSurface = null;
628 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700629 }
Jeff Brown96307042012-07-27 15:51:34 -0700630
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700631 private void destroySurface() {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800632 if (mSurfaceControl != null) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800633 mSurfaceLayout.dispose();
634 mSurfaceLayout = null;
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800635 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700636 try {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800637 mSurfaceControl.destroy();
638 mSurface.release();
Jeff Brown96307042012-07-27 15:51:34 -0700639 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800640 SurfaceControl.closeTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700641 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800642 mSurfaceControl = null;
Jeff Brown96307042012-07-27 15:51:34 -0700643 mSurfaceVisible = false;
Jeff Brown252c2062012-10-08 16:21:01 -0700644 mSurfaceAlpha = 0f;
Jeff Brown96307042012-07-27 15:51:34 -0700645 }
646 }
647
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700648 private boolean showSurface(float alpha) {
Jeff Brown252c2062012-10-08 16:21:01 -0700649 if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800650 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700651 try {
Michael Lentine0839adb2014-07-29 18:47:56 -0700652 mSurfaceControl.setLayer(COLOR_FADE_LAYER);
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800653 mSurfaceControl.setAlpha(alpha);
654 mSurfaceControl.show();
Jeff Brown96307042012-07-27 15:51:34 -0700655 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800656 SurfaceControl.closeTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700657 }
658 mSurfaceVisible = true;
Jeff Brown252c2062012-10-08 16:21:01 -0700659 mSurfaceAlpha = alpha;
Jeff Brown96307042012-07-27 15:51:34 -0700660 }
661 return true;
662 }
663
664 private boolean attachEglContext() {
665 if (mEglSurface == null) {
666 return false;
667 }
668 if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
669 logEglError("eglMakeCurrent");
670 return false;
671 }
672 return true;
673 }
674
675 private void detachEglContext() {
676 if (mEglDisplay != null) {
677 EGL14.eglMakeCurrent(mEglDisplay,
678 EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
679 }
680 }
681
Jeff Brown96307042012-07-27 15:51:34 -0700682 private static FloatBuffer createNativeFloatBuffer(int size) {
683 ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
684 bb.order(ByteOrder.nativeOrder());
685 return bb.asFloatBuffer();
686 }
687
688 private static void logEglError(String func) {
689 Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable());
690 }
691
692 private static boolean checkGlErrors(String func) {
693 return checkGlErrors(func, true);
694 }
695
696 private static boolean checkGlErrors(String func, boolean log) {
697 boolean hadError = false;
698 int error;
Michael Lentine0839adb2014-07-29 18:47:56 -0700699 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Jeff Brown96307042012-07-27 15:51:34 -0700700 if (log) {
701 Slog.e(TAG, func + " failed: error " + error, new Throwable());
702 }
703 hadError = true;
704 }
705 return hadError;
706 }
707
708 public void dump(PrintWriter pw) {
709 pw.println();
Michael Lentine0839adb2014-07-29 18:47:56 -0700710 pw.println("Color Fade State:");
Jeff Brown96307042012-07-27 15:51:34 -0700711 pw.println(" mPrepared=" + mPrepared);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700712 pw.println(" mMode=" + mMode);
Jeff Brown96307042012-07-27 15:51:34 -0700713 pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
Jeff Brown96307042012-07-27 15:51:34 -0700714 pw.println(" mDisplayWidth=" + mDisplayWidth);
715 pw.println(" mDisplayHeight=" + mDisplayHeight);
716 pw.println(" mSurfaceVisible=" + mSurfaceVisible);
Jeff Brown252c2062012-10-08 16:21:01 -0700717 pw.println(" mSurfaceAlpha=" + mSurfaceAlpha);
Jeff Brown96307042012-07-27 15:51:34 -0700718 }
Jeff Brown7f3994e2012-12-04 14:04:28 -0800719
720 /**
721 * Keeps a surface aligned with the natural orientation of the device.
722 * Updates the position and transformation of the matrix whenever the display
723 * is rotated. This is a little tricky because the display transaction
724 * callback can be invoked on any thread, not necessarily the thread that
Michael Lentine0839adb2014-07-29 18:47:56 -0700725 * owns the color fade.
Jeff Brown7f3994e2012-12-04 14:04:28 -0800726 */
727 private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
Jeff Brown4ccb8232014-01-16 22:16:42 -0800728 private final DisplayManagerInternal mDisplayManagerInternal;
Jeff Brown037c33e2014-04-09 00:31:55 -0700729 private final int mDisplayId;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800730 private SurfaceControl mSurfaceControl;
Jeff Brown7f3994e2012-12-04 14:04:28 -0800731
Jeff Brown4ccb8232014-01-16 22:16:42 -0800732 public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
Jeff Brown037c33e2014-04-09 00:31:55 -0700733 int displayId, SurfaceControl surfaceControl) {
Jeff Brown4ccb8232014-01-16 22:16:42 -0800734 mDisplayManagerInternal = displayManagerInternal;
Jeff Brown037c33e2014-04-09 00:31:55 -0700735 mDisplayId = displayId;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800736 mSurfaceControl = surfaceControl;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800737 mDisplayManagerInternal.registerDisplayTransactionListener(this);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800738 }
739
740 public void dispose() {
741 synchronized (this) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800742 mSurfaceControl = null;
Jeff Brown7f3994e2012-12-04 14:04:28 -0800743 }
Jeff Brown4ccb8232014-01-16 22:16:42 -0800744 mDisplayManagerInternal.unregisterDisplayTransactionListener(this);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800745 }
746
747 @Override
748 public void onDisplayTransaction() {
749 synchronized (this) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800750 if (mSurfaceControl == null) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800751 return;
752 }
753
Jeff Brown037c33e2014-04-09 00:31:55 -0700754 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800755 switch (displayInfo.rotation) {
756 case Surface.ROTATION_0:
Mathias Agopian29479eb2013-02-14 14:36:04 -0800757 mSurfaceControl.setPosition(0, 0);
758 mSurfaceControl.setMatrix(1, 0, 0, 1);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800759 break;
760 case Surface.ROTATION_90:
Mathias Agopian29479eb2013-02-14 14:36:04 -0800761 mSurfaceControl.setPosition(0, displayInfo.logicalHeight);
762 mSurfaceControl.setMatrix(0, -1, 1, 0);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800763 break;
764 case Surface.ROTATION_180:
Michael Lentine0839adb2014-07-29 18:47:56 -0700765 mSurfaceControl.setPosition(displayInfo.logicalWidth,
766 displayInfo.logicalHeight);
Mathias Agopian29479eb2013-02-14 14:36:04 -0800767 mSurfaceControl.setMatrix(-1, 0, 0, -1);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800768 break;
769 case Surface.ROTATION_270:
Mathias Agopian29479eb2013-02-14 14:36:04 -0800770 mSurfaceControl.setPosition(displayInfo.logicalWidth, 0);
771 mSurfaceControl.setMatrix(0, 1, -1, 0);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800772 break;
773 }
774 }
775 }
776 }
Jeff Brown96307042012-07-27 15:51:34 -0700777}