blob: bb4dbc3b5c9a65f6ffb08d43efe48e7a5b69e7f8 [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;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -070077 private int mMode;
Jeff Brown96307042012-07-27 15:51:34 -070078
Jeff Brown4ccb8232014-01-16 22:16:42 -080079 private final DisplayManagerInternal mDisplayManagerInternal;
Jeff Brown96307042012-07-27 15:51:34 -070080 private int mDisplayLayerStack; // layer stack associated with primary display
Jeff Brown96307042012-07-27 15:51:34 -070081 private int mDisplayWidth; // real width, not rotated
82 private int mDisplayHeight; // real height, not rotated
83 private SurfaceSession mSurfaceSession;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080084 private SurfaceControl mSurfaceControl;
Mathias Agopian86e1bc72013-03-13 17:48:22 -070085 private Surface mSurface;
Jeff Brown7f3994e2012-12-04 14:04:28 -080086 private NaturalSurfaceLayout mSurfaceLayout;
Jeff Brown96307042012-07-27 15:51:34 -070087 private EGLDisplay mEglDisplay;
88 private EGLConfig mEglConfig;
89 private EGLContext mEglContext;
90 private EGLSurface mEglSurface;
91 private boolean mSurfaceVisible;
Jeff Brown252c2062012-10-08 16:21:01 -070092 private float mSurfaceAlpha;
Jeff Brown96307042012-07-27 15:51:34 -070093
94 // Texture names. We only use one texture, which contains the screenshot.
95 private final int[] mTexNames = new int[1];
96 private boolean mTexNamesGenerated;
Igor Murashkina86ab6402013-08-30 12:58:36 -070097 private final float mTexMatrix[] = new float[16];
Michael Lentine0839adb2014-07-29 18:47:56 -070098 private final float mProjMatrix[] = new float[16];
99 private final int[] mGLBuffers = new int[2];
100 private int mTexCoordLoc, mVertexLoc, mTexUnitLoc, mProjMatrixLoc, mTexMatrixLoc;
101 private int mOpacityLoc, mScaleLoc, mGammaLoc, mSaturationLoc;
102 private int mProgram;
Jeff Brown96307042012-07-27 15:51:34 -0700103
104 // Vertex and corresponding texture coordinates.
105 // We have 4 2D vertices, so 8 elements. The vertices form a quad.
106 private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
107 private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
108
Jeff Brown252c2062012-10-08 16:21:01 -0700109 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700110 * Animates an color fade warming up.
Jeff Brown252c2062012-10-08 16:21:01 -0700111 */
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700112 public static final int MODE_WARM_UP = 0;
Jeff Brown252c2062012-10-08 16:21:01 -0700113
114 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700115 * Animates an color fade shutting off.
Jeff Brown252c2062012-10-08 16:21:01 -0700116 */
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700117 public static final int MODE_COOL_DOWN = 1;
Jeff Brown252c2062012-10-08 16:21:01 -0700118
119 /**
120 * Animates a simple dim layer to fade the contents of the screen in or out progressively.
121 */
122 public static final int MODE_FADE = 2;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700123
Michael Lentine0839adb2014-07-29 18:47:56 -0700124 public ColorFade(int displayId) {
Jeff Brown037c33e2014-04-09 00:31:55 -0700125 mDisplayId = displayId;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800126 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
Jeff Brown96307042012-07-27 15:51:34 -0700127 }
128
129 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700130 * Warms up the color fade in preparation for turning on or off.
Jeff Brown96307042012-07-27 15:51:34 -0700131 * This method prepares a GL context, and captures a screen shot.
132 *
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700133 * @param mode The desired mode for the upcoming animation.
Michael Lentine0839adb2014-07-29 18:47:56 -0700134 * @return True if the color fade is ready, false if it is uncontrollable.
Jeff Brown96307042012-07-27 15:51:34 -0700135 */
Michael Lentine0839adb2014-07-29 18:47:56 -0700136 public boolean prepare(Context context, int mode) {
Jeff Brown96307042012-07-27 15:51:34 -0700137 if (DEBUG) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700138 Slog.d(TAG, "prepare: mode=" + mode);
Jeff Brown96307042012-07-27 15:51:34 -0700139 }
140
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700141 mMode = mode;
Jeff Brown96307042012-07-27 15:51:34 -0700142
Jeff Brown7f3994e2012-12-04 14:04:28 -0800143 // Get the display size and layer stack.
Michael Lentine0839adb2014-07-29 18:47:56 -0700144 // This is not expected to change while the color fade surface is showing.
Jeff Brown037c33e2014-04-09 00:31:55 -0700145 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800146 mDisplayLayerStack = displayInfo.layerStack;
147 mDisplayWidth = displayInfo.getNaturalWidth();
148 mDisplayHeight = displayInfo.getNaturalHeight();
Jeff Brown96307042012-07-27 15:51:34 -0700149
150 // Prepare the surface for drawing.
Michael Lentine0839adb2014-07-29 18:47:56 -0700151 if (!(createSurface() && createEglContext() && createEglSurface() &&
152 captureScreenshotTextureAndSetViewport())) {
Jeff Brown96307042012-07-27 15:51:34 -0700153 dismiss();
154 return false;
155 }
156
Michael Lentine0839adb2014-07-29 18:47:56 -0700157 // Init GL
158 if (!attachEglContext()) {
159 return false;
160 }
161 try {
162 if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
163 detachEglContext();
164 dismiss();
165 return false;
166 }
167 } finally {
168 detachEglContext();
169 }
170
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700171 // Done.
Jeff Brown96307042012-07-27 15:51:34 -0700172 mPrepared = true;
Jeff Brown78eb1222012-10-10 18:27:44 -0700173
174 // Dejanking optimization.
175 // Some GL drivers can introduce a lot of lag in the first few frames as they
176 // initialize their state and allocate graphics buffers for rendering.
177 // Work around this problem by rendering the first frame of the animation a few
178 // times. The rest of the animation should run smoothly thereafter.
179 // The frames we draw here aren't visible because we are essentially just
180 // painting the screenshot as-is.
181 if (mode == MODE_COOL_DOWN) {
182 for (int i = 0; i < DEJANK_FRAMES; i++) {
183 draw(1.0f);
184 }
185 }
Jeff Brown96307042012-07-27 15:51:34 -0700186 return true;
187 }
188
Michael Lentine0839adb2014-07-29 18:47:56 -0700189 private String readFile(Context context, int resourceId) {
190 try{
191 InputStream stream = context.getResources().openRawResource(resourceId);
192 return new String(Streams.readFully(new InputStreamReader(stream)));
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700193 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700194 catch (IOException e) {
195 Slog.e(TAG, "Unrecognized shader " + Integer.toString(resourceId));
196 throw new RuntimeException(e);
197 }
198 }
199
200 private int loadShader(Context context, int resourceId, int type) {
201 String source = readFile(context, resourceId);
202
203 int shader = GLES20.glCreateShader(type);
204
205 GLES20.glShaderSource(shader, source);
206 GLES20.glCompileShader(shader);
207
208 int[] compiled = new int[1];
209 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
210 if (compiled[0] == 0) {
211 Slog.e(TAG, "Could not compile shader " + shader + ", " + type + ":");
212 Slog.e(TAG, GLES20.glGetShaderSource(shader));
213 Slog.e(TAG, GLES20.glGetShaderInfoLog(shader));
214 GLES20.glDeleteShader(shader);
215 shader = 0;
216 }
217
218 return shader;
219 }
220
221 private boolean initGLShaders(Context context) {
222 int vshader = loadShader(context, com.android.internal.R.raw.color_fade_vert,
223 GLES20.GL_VERTEX_SHADER);
224 int fshader = loadShader(context, com.android.internal.R.raw.color_fade_frag,
225 GLES20.GL_FRAGMENT_SHADER);
Michael Wright5018df72014-10-08 17:46:09 -0700226 GLES20.glReleaseShaderCompiler();
Michael Lentine0839adb2014-07-29 18:47:56 -0700227 if (vshader == 0 || fshader == 0) return false;
228
229 mProgram = GLES20.glCreateProgram();
230
231 GLES20.glAttachShader(mProgram, vshader);
232 GLES20.glAttachShader(mProgram, fshader);
Michael Wright5018df72014-10-08 17:46:09 -0700233 GLES20.glDeleteShader(vshader);
234 GLES20.glDeleteShader(fshader);
Michael Lentine0839adb2014-07-29 18:47:56 -0700235
236 GLES20.glLinkProgram(mProgram);
237
238 mVertexLoc = GLES20.glGetAttribLocation(mProgram, "position");
239 mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "uv");
240
241 mProjMatrixLoc = GLES20.glGetUniformLocation(mProgram, "proj_matrix");
242 mTexMatrixLoc = GLES20.glGetUniformLocation(mProgram, "tex_matrix");
243
244 mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity");
245 mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma");
246 mSaturationLoc = GLES20.glGetUniformLocation(mProgram, "saturation");
247 mScaleLoc = GLES20.glGetUniformLocation(mProgram, "scale");
248 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 Lentine0839adb2014-07-29 18:47:56 -0700316 * Dismisses the color fade animation surface and cleans up.
Jeff Brown96307042012-07-27 15:51:34 -0700317 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700318 * To prevent stray photons from leaking out after the color fade has been
Jeff Brown96307042012-07-27 15:51:34 -0700319 * turned off, it is a good idea to defer dismissing the animation until the
Michael Lentine0839adb2014-07-29 18:47:56 -0700320 * color fade has been turned back on fully.
Jeff Brown96307042012-07-27 15:51:34 -0700321 */
322 public void dismiss() {
323 if (DEBUG) {
324 Slog.d(TAG, "dismiss");
325 }
326
Michael Wright5018df72014-10-08 17:46:09 -0700327 if (mPrepared) {
328 attachEglContext();
329 try {
330 destroyScreenshotTexture();
331 destroyGLShaders();
332 destroyGLBuffers();
333 destroyEglSurface();
334 } finally {
335 detachEglContext();
336 }
337 destroySurface();
338 GLES20.glFlush();
339 mPrepared = false;
340 }
Jeff Brown96307042012-07-27 15:51:34 -0700341 }
342
343 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700344 * Draws an animation frame showing the color fade activated at the
Jeff Brown96307042012-07-27 15:51:34 -0700345 * specified level.
346 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700347 * @param level The color fade level.
Jeff Brown96307042012-07-27 15:51:34 -0700348 * @return True if successful.
349 */
350 public boolean draw(float level) {
351 if (DEBUG) {
352 Slog.d(TAG, "drawFrame: level=" + level);
353 }
354
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700355 if (!mPrepared) {
356 return false;
357 }
358
Jeff Brown252c2062012-10-08 16:21:01 -0700359 if (mMode == MODE_FADE) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700360 return showSurface(1.0f - level);
361 }
362
Jeff Brown96307042012-07-27 15:51:34 -0700363 if (!attachEglContext()) {
364 return false;
365 }
366 try {
367 // Clear frame to solid black.
Michael Lentine0839adb2014-07-29 18:47:56 -0700368 GLES20.glClearColor(0f, 0f, 0f, 1f);
369 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Jeff Brown96307042012-07-27 15:51:34 -0700370
371 // Draw the frame.
Neil Fullere573aa92015-02-11 15:49:47 +0000372 double one_minus_level = 1 - level;
373 double cos = Math.cos(Math.PI * one_minus_level);
374 double sign = cos < 0 ? -1 : 1;
375 float opacity = (float) -Math.pow(one_minus_level, 2) + 1;
376 float saturation = (float) Math.pow(level, 4);
377 float scale = (float) ((-Math.pow(one_minus_level, 2) + 1) * 0.1d + 0.9d);
378 float gamma = (float) ((0.5d * sign * Math.pow(cos, 2) + 0.5d) * 0.9d + 0.1d);
Michael Lentine0839adb2014-07-29 18:47:56 -0700379 drawFaded(opacity, 1.f / gamma, saturation, scale);
Jeff Brown96307042012-07-27 15:51:34 -0700380 if (checkGlErrors("drawFrame")) {
381 return false;
382 }
383
384 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
385 } finally {
386 detachEglContext();
387 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700388 return showSurface(1.0f);
Jeff Brown96307042012-07-27 15:51:34 -0700389 }
390
Michael Lentine0839adb2014-07-29 18:47:56 -0700391 private void drawFaded(float opacity, float gamma, float saturation, float scale) {
Jeff Brown96307042012-07-27 15:51:34 -0700392 if (DEBUG) {
Michael Lentine0839adb2014-07-29 18:47:56 -0700393 Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma +
394 ", saturation=" + saturation + ", scale=" + scale);
Jeff Brown96307042012-07-27 15:51:34 -0700395 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700396 // Use shaders
397 GLES20.glUseProgram(mProgram);
Jeff Brown96307042012-07-27 15:51:34 -0700398
Michael Lentine0839adb2014-07-29 18:47:56 -0700399 // Set Uniforms
400 GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0);
401 GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
402 GLES20.glUniform1f(mOpacityLoc, opacity);
403 GLES20.glUniform1f(mGammaLoc, gamma);
404 GLES20.glUniform1f(mSaturationLoc, saturation);
405 GLES20.glUniform1f(mScaleLoc, scale);
Jeff Brown96307042012-07-27 15:51:34 -0700406
Michael Lentine0839adb2014-07-29 18:47:56 -0700407 // Use textures
408 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
409 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
Jeff Brown96307042012-07-27 15:51:34 -0700410
Michael Lentine0839adb2014-07-29 18:47:56 -0700411 // draw the plane
412 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
413 GLES20.glEnableVertexAttribArray(mVertexLoc);
414 GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800415
Michael Lentine0839adb2014-07-29 18:47:56 -0700416 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
417 GLES20.glEnableVertexAttribArray(mTexCoordLoc);
418 GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700419
Michael Lentine0839adb2014-07-29 18:47:56 -0700420 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
Jeff Brown96307042012-07-27 15:51:34 -0700421
422 // clean up
Michael Lentine0839adb2014-07-29 18:47:56 -0700423 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
424 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700425 }
426
Michael Lentine0839adb2014-07-29 18:47:56 -0700427 private void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
428 mProjMatrix[0] = 2f / (right - left);
429 mProjMatrix[1] = 0;
430 mProjMatrix[2] = 0;
431 mProjMatrix[3] = 0;
432 mProjMatrix[4] = 0;
433 mProjMatrix[5] = 2f / (top - bottom);
434 mProjMatrix[6] = 0;
435 mProjMatrix[7] = 0;
436 mProjMatrix[8] = 0;
437 mProjMatrix[9] = 0;
438 mProjMatrix[10] = -2f / (zfar - znear);
439 mProjMatrix[11] = 0;
440 mProjMatrix[12] = -(right + left) / (right - left);
441 mProjMatrix[13] = -(top + bottom) / (top - bottom);
442 mProjMatrix[14] = -(zfar + znear) / (zfar - znear);
443 mProjMatrix[15] = 1f;
Jeff Brown96307042012-07-27 15:51:34 -0700444 }
445
446 private boolean captureScreenshotTextureAndSetViewport() {
Mathias Agopian0449a402013-03-01 23:01:51 -0800447 if (!attachEglContext()) {
Jeff Brown96307042012-07-27 15:51:34 -0700448 return false;
449 }
450 try {
Mathias Agopian0449a402013-03-01 23:01:51 -0800451 if (!mTexNamesGenerated) {
Michael Lentine0839adb2014-07-29 18:47:56 -0700452 GLES20.glGenTextures(1, mTexNames, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800453 if (checkGlErrors("glGenTextures")) {
Jeff Brown96307042012-07-27 15:51:34 -0700454 return false;
455 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800456 mTexNamesGenerated = true;
Jeff Brown96307042012-07-27 15:51:34 -0700457 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800458
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700459 final SurfaceTexture st = new SurfaceTexture(mTexNames[0]);
460 final Surface s = new Surface(st);
461 try {
462 SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
463 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), s);
Michael Wright2ed05132015-01-08 14:30:47 -0800464 st.updateTexImage();
465 st.getTransformMatrix(mTexMatrix);
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700466 } finally {
467 s.release();
Michael Wright2ed05132015-01-08 14:30:47 -0800468 st.release();
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700469 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800470
Mathias Agopian0449a402013-03-01 23:01:51 -0800471 // Set up texture coordinates for a quad.
472 // We might need to change this if the texture ends up being
473 // a different size from the display for some reason.
474 mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f);
475 mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f);
476 mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f);
477 mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
478
479 // Set up our viewport.
Michael Lentine0839adb2014-07-29 18:47:56 -0700480 GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
481 ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1);
Jeff Brown96307042012-07-27 15:51:34 -0700482 } finally {
Mathias Agopian0449a402013-03-01 23:01:51 -0800483 detachEglContext();
Jeff Brown96307042012-07-27 15:51:34 -0700484 }
485 return true;
486 }
487
488 private void destroyScreenshotTexture() {
489 if (mTexNamesGenerated) {
490 mTexNamesGenerated = false;
Michael Wright5018df72014-10-08 17:46:09 -0700491 GLES20.glDeleteTextures(1, mTexNames, 0);
492 checkGlErrors("glDeleteTextures");
Jeff Brown96307042012-07-27 15:51:34 -0700493 }
494 }
495
496 private boolean createEglContext() {
497 if (mEglDisplay == null) {
498 mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
499 if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
500 logEglError("eglGetDisplay");
501 return false;
502 }
503
504 int[] version = new int[2];
505 if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
506 mEglDisplay = null;
507 logEglError("eglInitialize");
508 return false;
509 }
510 }
511
512 if (mEglConfig == null) {
513 int[] eglConfigAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700514 EGL14.EGL_RENDERABLE_TYPE,
515 EGL14.EGL_OPENGL_ES2_BIT,
Jeff Brown96307042012-07-27 15:51:34 -0700516 EGL14.EGL_RED_SIZE, 8,
517 EGL14.EGL_GREEN_SIZE, 8,
518 EGL14.EGL_BLUE_SIZE, 8,
519 EGL14.EGL_ALPHA_SIZE, 8,
520 EGL14.EGL_NONE
521 };
522 int[] numEglConfigs = new int[1];
523 EGLConfig[] eglConfigs = new EGLConfig[1];
524 if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0,
525 eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) {
526 logEglError("eglChooseConfig");
527 return false;
528 }
529 mEglConfig = eglConfigs[0];
530 }
531
532 if (mEglContext == null) {
533 int[] eglContextAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700534 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
Jeff Brown96307042012-07-27 15:51:34 -0700535 EGL14.EGL_NONE
536 };
537 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
538 EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
539 if (mEglContext == null) {
540 logEglError("eglCreateContext");
541 return false;
542 }
543 }
544 return true;
545 }
546
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700547 private boolean createSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700548 if (mSurfaceSession == null) {
549 mSurfaceSession = new SurfaceSession();
550 }
551
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800552 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700553 try {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800554 if (mSurfaceControl == null) {
Jeff Brown96307042012-07-27 15:51:34 -0700555 try {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700556 int flags;
Jeff Brown252c2062012-10-08 16:21:01 -0700557 if (mMode == MODE_FADE) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800558 flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700559 } else {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800560 flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700561 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800562 mSurfaceControl = new SurfaceControl(mSurfaceSession,
Michael Lentine0839adb2014-07-29 18:47:56 -0700563 "ColorFade", mDisplayWidth, mDisplayHeight,
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700564 PixelFormat.OPAQUE, flags);
Igor Murashkina86ab6402013-08-30 12:58:36 -0700565 } catch (OutOfResourcesException ex) {
Jeff Brown96307042012-07-27 15:51:34 -0700566 Slog.e(TAG, "Unable to create surface.", ex);
567 return false;
568 }
569 }
570
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800571 mSurfaceControl.setLayerStack(mDisplayLayerStack);
572 mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700573 mSurface = new Surface();
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800574 mSurface.copyFrom(mSurfaceControl);
Igor Murashkina86ab6402013-08-30 12:58:36 -0700575
Jeff Brown037c33e2014-04-09 00:31:55 -0700576 mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
577 mDisplayId, mSurfaceControl);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800578 mSurfaceLayout.onDisplayTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700579 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800580 SurfaceControl.closeTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700581 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700582 return true;
583 }
Jeff Brown96307042012-07-27 15:51:34 -0700584
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700585 private boolean createEglSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700586 if (mEglSurface == null) {
587 int[] eglSurfaceAttribList = new int[] {
588 EGL14.EGL_NONE
589 };
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800590 // turn our SurfaceControl into a Surface
Jeff Brown96307042012-07-27 15:51:34 -0700591 mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
592 eglSurfaceAttribList, 0);
593 if (mEglSurface == null) {
594 logEglError("eglCreateWindowSurface");
595 return false;
596 }
597 }
598 return true;
599 }
600
601 private void destroyEglSurface() {
602 if (mEglSurface != null) {
603 if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) {
604 logEglError("eglDestroySurface");
605 }
606 mEglSurface = null;
607 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700608 }
Jeff Brown96307042012-07-27 15:51:34 -0700609
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700610 private void destroySurface() {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800611 if (mSurfaceControl != null) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800612 mSurfaceLayout.dispose();
613 mSurfaceLayout = null;
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800614 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700615 try {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800616 mSurfaceControl.destroy();
617 mSurface.release();
Jeff Brown96307042012-07-27 15:51:34 -0700618 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800619 SurfaceControl.closeTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700620 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800621 mSurfaceControl = null;
Jeff Brown96307042012-07-27 15:51:34 -0700622 mSurfaceVisible = false;
Jeff Brown252c2062012-10-08 16:21:01 -0700623 mSurfaceAlpha = 0f;
Jeff Brown96307042012-07-27 15:51:34 -0700624 }
625 }
626
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700627 private boolean showSurface(float alpha) {
Jeff Brown252c2062012-10-08 16:21:01 -0700628 if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800629 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700630 try {
Michael Lentine0839adb2014-07-29 18:47:56 -0700631 mSurfaceControl.setLayer(COLOR_FADE_LAYER);
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800632 mSurfaceControl.setAlpha(alpha);
633 mSurfaceControl.show();
Jeff Brown96307042012-07-27 15:51:34 -0700634 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800635 SurfaceControl.closeTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700636 }
637 mSurfaceVisible = true;
Jeff Brown252c2062012-10-08 16:21:01 -0700638 mSurfaceAlpha = alpha;
Jeff Brown96307042012-07-27 15:51:34 -0700639 }
640 return true;
641 }
642
643 private boolean attachEglContext() {
644 if (mEglSurface == null) {
645 return false;
646 }
647 if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
648 logEglError("eglMakeCurrent");
649 return false;
650 }
651 return true;
652 }
653
654 private void detachEglContext() {
655 if (mEglDisplay != null) {
656 EGL14.eglMakeCurrent(mEglDisplay,
657 EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
658 }
659 }
660
Jeff Brown96307042012-07-27 15:51:34 -0700661 private static FloatBuffer createNativeFloatBuffer(int size) {
662 ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
663 bb.order(ByteOrder.nativeOrder());
664 return bb.asFloatBuffer();
665 }
666
667 private static void logEglError(String func) {
668 Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable());
669 }
670
671 private static boolean checkGlErrors(String func) {
672 return checkGlErrors(func, true);
673 }
674
675 private static boolean checkGlErrors(String func, boolean log) {
676 boolean hadError = false;
677 int error;
Michael Lentine0839adb2014-07-29 18:47:56 -0700678 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Jeff Brown96307042012-07-27 15:51:34 -0700679 if (log) {
680 Slog.e(TAG, func + " failed: error " + error, new Throwable());
681 }
682 hadError = true;
683 }
684 return hadError;
685 }
686
687 public void dump(PrintWriter pw) {
688 pw.println();
Michael Lentine0839adb2014-07-29 18:47:56 -0700689 pw.println("Color Fade State:");
Jeff Brown96307042012-07-27 15:51:34 -0700690 pw.println(" mPrepared=" + mPrepared);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700691 pw.println(" mMode=" + mMode);
Jeff Brown96307042012-07-27 15:51:34 -0700692 pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
Jeff Brown96307042012-07-27 15:51:34 -0700693 pw.println(" mDisplayWidth=" + mDisplayWidth);
694 pw.println(" mDisplayHeight=" + mDisplayHeight);
695 pw.println(" mSurfaceVisible=" + mSurfaceVisible);
Jeff Brown252c2062012-10-08 16:21:01 -0700696 pw.println(" mSurfaceAlpha=" + mSurfaceAlpha);
Jeff Brown96307042012-07-27 15:51:34 -0700697 }
Jeff Brown7f3994e2012-12-04 14:04:28 -0800698
699 /**
700 * Keeps a surface aligned with the natural orientation of the device.
701 * Updates the position and transformation of the matrix whenever the display
702 * is rotated. This is a little tricky because the display transaction
703 * callback can be invoked on any thread, not necessarily the thread that
Michael Lentine0839adb2014-07-29 18:47:56 -0700704 * owns the color fade.
Jeff Brown7f3994e2012-12-04 14:04:28 -0800705 */
706 private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
Jeff Brown4ccb8232014-01-16 22:16:42 -0800707 private final DisplayManagerInternal mDisplayManagerInternal;
Jeff Brown037c33e2014-04-09 00:31:55 -0700708 private final int mDisplayId;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800709 private SurfaceControl mSurfaceControl;
Jeff Brown7f3994e2012-12-04 14:04:28 -0800710
Jeff Brown4ccb8232014-01-16 22:16:42 -0800711 public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
Jeff Brown037c33e2014-04-09 00:31:55 -0700712 int displayId, SurfaceControl surfaceControl) {
Jeff Brown4ccb8232014-01-16 22:16:42 -0800713 mDisplayManagerInternal = displayManagerInternal;
Jeff Brown037c33e2014-04-09 00:31:55 -0700714 mDisplayId = displayId;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800715 mSurfaceControl = surfaceControl;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800716 mDisplayManagerInternal.registerDisplayTransactionListener(this);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800717 }
718
719 public void dispose() {
720 synchronized (this) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800721 mSurfaceControl = null;
Jeff Brown7f3994e2012-12-04 14:04:28 -0800722 }
Jeff Brown4ccb8232014-01-16 22:16:42 -0800723 mDisplayManagerInternal.unregisterDisplayTransactionListener(this);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800724 }
725
726 @Override
727 public void onDisplayTransaction() {
728 synchronized (this) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800729 if (mSurfaceControl == null) {
Jeff Brown7f3994e2012-12-04 14:04:28 -0800730 return;
731 }
732
Jeff Brown037c33e2014-04-09 00:31:55 -0700733 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800734 switch (displayInfo.rotation) {
735 case Surface.ROTATION_0:
Mathias Agopian29479eb2013-02-14 14:36:04 -0800736 mSurfaceControl.setPosition(0, 0);
737 mSurfaceControl.setMatrix(1, 0, 0, 1);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800738 break;
739 case Surface.ROTATION_90:
Mathias Agopian29479eb2013-02-14 14:36:04 -0800740 mSurfaceControl.setPosition(0, displayInfo.logicalHeight);
741 mSurfaceControl.setMatrix(0, -1, 1, 0);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800742 break;
743 case Surface.ROTATION_180:
Michael Lentine0839adb2014-07-29 18:47:56 -0700744 mSurfaceControl.setPosition(displayInfo.logicalWidth,
745 displayInfo.logicalHeight);
Mathias Agopian29479eb2013-02-14 14:36:04 -0800746 mSurfaceControl.setMatrix(-1, 0, 0, -1);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800747 break;
748 case Surface.ROTATION_270:
Mathias Agopian29479eb2013-02-14 14:36:04 -0800749 mSurfaceControl.setPosition(displayInfo.logicalWidth, 0);
750 mSurfaceControl.setMatrix(0, 1, -1, 0);
Jeff Brown7f3994e2012-12-04 14:04:28 -0800751 break;
752 }
753 }
754 }
755 }
Jeff Brown96307042012-07-27 15:51:34 -0700756}