blob: a16fcd2fa112e962a12a2dfd8c8e59498f43c837 [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;
102 private int mOpacityLoc, mScaleLoc, mGammaLoc, mSaturationLoc;
103 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");
248 mSaturationLoc = GLES20.glGetUniformLocation(mProgram, "saturation");
249 mScaleLoc = GLES20.glGetUniformLocation(mProgram, "scale");
250 mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit");
251
252 GLES20.glUseProgram(mProgram);
253 GLES20.glUniform1i(mTexUnitLoc, 0);
254 GLES20.glUseProgram(0);
255
256 return true;
257 }
258
Michael Wright5018df72014-10-08 17:46:09 -0700259 private void destroyGLShaders() {
260 GLES20.glDeleteProgram(mProgram);
261 checkGlErrors("glDeleteProgram");
262 }
263
Michael Lentine0839adb2014-07-29 18:47:56 -0700264 private boolean initGLBuffers() {
265 //Fill vertices
266 setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight);
267
268 // Setup GL Textures
269 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
270 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
271 GLES20.GL_NEAREST);
272 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
273 GLES20.GL_NEAREST);
274 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
275 GLES20.GL_CLAMP_TO_EDGE);
276 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
277 GLES20.GL_CLAMP_TO_EDGE);
278 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
279
280 // Setup GL Buffers
281 GLES20.glGenBuffers(2, mGLBuffers, 0);
282
283 // fill vertex buffer
284 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
285 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4,
286 mVertexBuffer, GLES20.GL_STATIC_DRAW);
287
288 // fill tex buffer
289 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
290 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4,
291 mTexCoordBuffer, GLES20.GL_STATIC_DRAW);
292
293 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
294
295 return true;
296 }
297
Michael Wright5018df72014-10-08 17:46:09 -0700298 private void destroyGLBuffers() {
299 GLES20.glDeleteBuffers(2, mGLBuffers, 0);
300 checkGlErrors("glDeleteBuffers");
301 }
302
Michael Lentine0839adb2014-07-29 18:47:56 -0700303 private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
304 if (DEBUG) {
305 Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
306 }
307 vtx.put(0, x);
308 vtx.put(1, y);
309 vtx.put(2, x);
310 vtx.put(3, y + h);
311 vtx.put(4, x + w);
312 vtx.put(5, y + h);
313 vtx.put(6, x + w);
314 vtx.put(7, y);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700315 }
316
Jeff Brown96307042012-07-27 15:51:34 -0700317 /**
Michael Lentined73854d2015-09-25 10:55:26 -0700318 * Dismisses the color fade animation resources.
319 *
320 * This function destroys the resources that are created for the color fade
321 * animation but does not clean up the surface.
322 */
323 public void dismissResources() {
324 if (DEBUG) {
325 Slog.d(TAG, "dismissResources");
326 }
327
328 if (mCreatedResources) {
329 attachEglContext();
330 try {
331 destroyScreenshotTexture();
332 destroyGLShaders();
333 destroyGLBuffers();
334 destroyEglSurface();
335 } finally {
336 detachEglContext();
337 }
338 // This is being called with no active context so shouldn't be
339 // needed but is safer to not change for now.
340 GLES20.glFlush();
341 mCreatedResources = false;
342 }
343 }
344
345 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700346 * Dismisses the color fade animation surface and cleans up.
Jeff Brown96307042012-07-27 15:51:34 -0700347 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700348 * To prevent stray photons from leaking out after the color fade has been
Jeff Brown96307042012-07-27 15:51:34 -0700349 * turned off, it is a good idea to defer dismissing the animation until the
Michael Lentine0839adb2014-07-29 18:47:56 -0700350 * color fade has been turned back on fully.
Jeff Brown96307042012-07-27 15:51:34 -0700351 */
352 public void dismiss() {
353 if (DEBUG) {
354 Slog.d(TAG, "dismiss");
355 }
356
Michael Wright5018df72014-10-08 17:46:09 -0700357 if (mPrepared) {
Michael Lentined73854d2015-09-25 10:55:26 -0700358 dismissResources();
Michael Wright5018df72014-10-08 17:46:09 -0700359 destroySurface();
Michael Wright5018df72014-10-08 17:46:09 -0700360 mPrepared = false;
361 }
Jeff Brown96307042012-07-27 15:51:34 -0700362 }
363
364 /**
Michael Lentine0839adb2014-07-29 18:47:56 -0700365 * Draws an animation frame showing the color fade activated at the
Jeff Brown96307042012-07-27 15:51:34 -0700366 * specified level.
367 *
Michael Lentine0839adb2014-07-29 18:47:56 -0700368 * @param level The color fade level.
Jeff Brown96307042012-07-27 15:51:34 -0700369 * @return True if successful.
370 */
371 public boolean draw(float level) {
372 if (DEBUG) {
373 Slog.d(TAG, "drawFrame: level=" + level);
374 }
375
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700376 if (!mPrepared) {
377 return false;
378 }
379
Jeff Brown252c2062012-10-08 16:21:01 -0700380 if (mMode == MODE_FADE) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700381 return showSurface(1.0f - level);
382 }
383
Jeff Brown96307042012-07-27 15:51:34 -0700384 if (!attachEglContext()) {
385 return false;
386 }
387 try {
388 // Clear frame to solid black.
Michael Lentine0839adb2014-07-29 18:47:56 -0700389 GLES20.glClearColor(0f, 0f, 0f, 1f);
390 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Jeff Brown96307042012-07-27 15:51:34 -0700391
392 // Draw the frame.
Neil Fullere573aa92015-02-11 15:49:47 +0000393 double one_minus_level = 1 - level;
394 double cos = Math.cos(Math.PI * one_minus_level);
395 double sign = cos < 0 ? -1 : 1;
396 float opacity = (float) -Math.pow(one_minus_level, 2) + 1;
397 float saturation = (float) Math.pow(level, 4);
398 float scale = (float) ((-Math.pow(one_minus_level, 2) + 1) * 0.1d + 0.9d);
399 float gamma = (float) ((0.5d * sign * Math.pow(cos, 2) + 0.5d) * 0.9d + 0.1d);
Michael Lentine0839adb2014-07-29 18:47:56 -0700400 drawFaded(opacity, 1.f / gamma, saturation, scale);
Jeff Brown96307042012-07-27 15:51:34 -0700401 if (checkGlErrors("drawFrame")) {
402 return false;
403 }
404
405 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
406 } finally {
407 detachEglContext();
408 }
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700409 return showSurface(1.0f);
Jeff Brown96307042012-07-27 15:51:34 -0700410 }
411
Michael Lentine0839adb2014-07-29 18:47:56 -0700412 private void drawFaded(float opacity, float gamma, float saturation, float scale) {
Jeff Brown96307042012-07-27 15:51:34 -0700413 if (DEBUG) {
Michael Lentine0839adb2014-07-29 18:47:56 -0700414 Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma +
415 ", saturation=" + saturation + ", scale=" + scale);
Jeff Brown96307042012-07-27 15:51:34 -0700416 }
Michael Lentine0839adb2014-07-29 18:47:56 -0700417 // Use shaders
418 GLES20.glUseProgram(mProgram);
Jeff Brown96307042012-07-27 15:51:34 -0700419
Michael Lentine0839adb2014-07-29 18:47:56 -0700420 // Set Uniforms
421 GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0);
422 GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
423 GLES20.glUniform1f(mOpacityLoc, opacity);
424 GLES20.glUniform1f(mGammaLoc, gamma);
425 GLES20.glUniform1f(mSaturationLoc, saturation);
426 GLES20.glUniform1f(mScaleLoc, scale);
Jeff Brown96307042012-07-27 15:51:34 -0700427
Michael Lentine0839adb2014-07-29 18:47:56 -0700428 // Use textures
429 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
430 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
Jeff Brown96307042012-07-27 15:51:34 -0700431
Michael Lentine0839adb2014-07-29 18:47:56 -0700432 // draw the plane
433 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
434 GLES20.glEnableVertexAttribArray(mVertexLoc);
435 GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800436
Michael Lentine0839adb2014-07-29 18:47:56 -0700437 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
438 GLES20.glEnableVertexAttribArray(mTexCoordLoc);
439 GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700440
Michael Lentine0839adb2014-07-29 18:47:56 -0700441 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
Jeff Brown96307042012-07-27 15:51:34 -0700442
443 // clean up
Michael Lentine0839adb2014-07-29 18:47:56 -0700444 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
445 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
Jeff Brown96307042012-07-27 15:51:34 -0700446 }
447
Michael Lentine0839adb2014-07-29 18:47:56 -0700448 private void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
449 mProjMatrix[0] = 2f / (right - left);
450 mProjMatrix[1] = 0;
451 mProjMatrix[2] = 0;
452 mProjMatrix[3] = 0;
453 mProjMatrix[4] = 0;
454 mProjMatrix[5] = 2f / (top - bottom);
455 mProjMatrix[6] = 0;
456 mProjMatrix[7] = 0;
457 mProjMatrix[8] = 0;
458 mProjMatrix[9] = 0;
459 mProjMatrix[10] = -2f / (zfar - znear);
460 mProjMatrix[11] = 0;
461 mProjMatrix[12] = -(right + left) / (right - left);
462 mProjMatrix[13] = -(top + bottom) / (top - bottom);
463 mProjMatrix[14] = -(zfar + znear) / (zfar - znear);
464 mProjMatrix[15] = 1f;
Jeff Brown96307042012-07-27 15:51:34 -0700465 }
466
467 private boolean captureScreenshotTextureAndSetViewport() {
Mathias Agopian0449a402013-03-01 23:01:51 -0800468 if (!attachEglContext()) {
Jeff Brown96307042012-07-27 15:51:34 -0700469 return false;
470 }
471 try {
Mathias Agopian0449a402013-03-01 23:01:51 -0800472 if (!mTexNamesGenerated) {
Michael Lentine0839adb2014-07-29 18:47:56 -0700473 GLES20.glGenTextures(1, mTexNames, 0);
Mathias Agopian0449a402013-03-01 23:01:51 -0800474 if (checkGlErrors("glGenTextures")) {
Jeff Brown96307042012-07-27 15:51:34 -0700475 return false;
476 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800477 mTexNamesGenerated = true;
Jeff Brown96307042012-07-27 15:51:34 -0700478 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800479
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700480 final SurfaceTexture st = new SurfaceTexture(mTexNames[0]);
481 final Surface s = new Surface(st);
482 try {
483 SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
484 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), s);
Michael Wright2ed05132015-01-08 14:30:47 -0800485 st.updateTexImage();
486 st.getTransformMatrix(mTexMatrix);
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700487 } finally {
488 s.release();
Michael Wright2ed05132015-01-08 14:30:47 -0800489 st.release();
Jeff Sharkey21ef9642013-04-25 11:34:23 -0700490 }
Mathias Agopian0449a402013-03-01 23:01:51 -0800491
Mathias Agopian0449a402013-03-01 23:01:51 -0800492 // Set up texture coordinates for a quad.
493 // We might need to change this if the texture ends up being
494 // a different size from the display for some reason.
495 mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f);
496 mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f);
497 mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f);
498 mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
499
500 // Set up our viewport.
Michael Lentine0839adb2014-07-29 18:47:56 -0700501 GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
502 ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1);
Jeff Brown96307042012-07-27 15:51:34 -0700503 } finally {
Mathias Agopian0449a402013-03-01 23:01:51 -0800504 detachEglContext();
Jeff Brown96307042012-07-27 15:51:34 -0700505 }
506 return true;
507 }
508
509 private void destroyScreenshotTexture() {
510 if (mTexNamesGenerated) {
511 mTexNamesGenerated = false;
Michael Wright5018df72014-10-08 17:46:09 -0700512 GLES20.glDeleteTextures(1, mTexNames, 0);
513 checkGlErrors("glDeleteTextures");
Jeff Brown96307042012-07-27 15:51:34 -0700514 }
515 }
516
517 private boolean createEglContext() {
518 if (mEglDisplay == null) {
519 mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
520 if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
521 logEglError("eglGetDisplay");
522 return false;
523 }
524
525 int[] version = new int[2];
526 if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
527 mEglDisplay = null;
528 logEglError("eglInitialize");
529 return false;
530 }
531 }
532
533 if (mEglConfig == null) {
534 int[] eglConfigAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700535 EGL14.EGL_RENDERABLE_TYPE,
536 EGL14.EGL_OPENGL_ES2_BIT,
Jeff Brown96307042012-07-27 15:51:34 -0700537 EGL14.EGL_RED_SIZE, 8,
538 EGL14.EGL_GREEN_SIZE, 8,
539 EGL14.EGL_BLUE_SIZE, 8,
540 EGL14.EGL_ALPHA_SIZE, 8,
541 EGL14.EGL_NONE
542 };
543 int[] numEglConfigs = new int[1];
544 EGLConfig[] eglConfigs = new EGLConfig[1];
545 if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0,
546 eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) {
547 logEglError("eglChooseConfig");
548 return false;
549 }
550 mEglConfig = eglConfigs[0];
551 }
552
553 if (mEglContext == null) {
554 int[] eglContextAttribList = new int[] {
Michael Lentine0839adb2014-07-29 18:47:56 -0700555 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
Jeff Brown96307042012-07-27 15:51:34 -0700556 EGL14.EGL_NONE
557 };
558 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
559 EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
560 if (mEglContext == null) {
561 logEglError("eglCreateContext");
562 return false;
563 }
564 }
565 return true;
566 }
567
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700568 private boolean createSurface() {
Jeff Brown96307042012-07-27 15:51:34 -0700569 if (mSurfaceSession == null) {
570 mSurfaceSession = new SurfaceSession();
571 }
572
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800573 SurfaceControl.openTransaction();
Jeff Brown96307042012-07-27 15:51:34 -0700574 try {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800575 if (mSurfaceControl == null) {
Jeff Brown96307042012-07-27 15:51:34 -0700576 try {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700577 int flags;
Jeff Brown252c2062012-10-08 16:21:01 -0700578 if (mMode == MODE_FADE) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800579 flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700580 } else {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800581 flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700582 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800583 mSurfaceControl = new SurfaceControl(mSurfaceSession,
Michael Lentine0839adb2014-07-29 18:47:56 -0700584 "ColorFade", mDisplayWidth, mDisplayHeight,
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700585 PixelFormat.OPAQUE, flags);
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}