blob: 3781bdb545acc8d7f9489f990500d77fc4aaee1b [file] [log] [blame]
Romain Guy2d614592010-06-09 18:21:37 -07001/*
Romain Guy735738c2012-12-03 12:34:51 -08002 * Copyright (C) 2013 The Android Open Source Project
Romain Guy2d614592010-06-09 18:21:37 -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
Romain Guy2d614592010-06-09 18:21:37 -070017package android.view;
18
Dianne Hackbornc68c9132011-07-29 01:25:18 -070019import android.content.ComponentCallbacks2;
Romain Guy78dd96d2013-05-03 14:24:16 -070020import android.graphics.Color;
Romain Guy7d7b5492011-01-24 16:33:45 -080021import android.graphics.Paint;
22import android.graphics.Rect;
Romain Guyaa6c24c2011-04-28 18:40:04 -070023import android.graphics.SurfaceTexture;
Romain Guybd431522012-09-26 13:31:25 -070024import android.opengl.EGL14;
Romain Guy407ec782011-08-24 17:06:58 -070025import android.opengl.GLUtils;
Dianne Hackborn717a25d2011-11-15 18:59:59 -080026import android.opengl.ManagedEGLContext;
27import android.os.Handler;
Romain Guy3b748a42013-04-17 18:54:38 -070028import android.os.IBinder;
Dianne Hackborn717a25d2011-11-15 18:59:59 -080029import android.os.Looper;
Romain Guy3b748a42013-04-17 18:54:38 -070030import android.os.RemoteException;
31import android.os.ServiceManager;
Romain Guy02ccac62011-06-24 13:20:23 -070032import android.os.SystemClock;
33import android.os.SystemProperties;
Romain Guy77e67cf2012-06-19 16:38:50 -070034import android.os.Trace;
Romain Guy98e4a522013-01-07 10:58:34 -080035import android.util.DisplayMetrics;
Romain Guye3924992010-06-10 18:51:21 -070036import android.util.Log;
Igor Murashkina86ab6402013-08-30 12:58:36 -070037import android.view.Surface.OutOfResourcesException;
38
Romain Guy8ff6b9e2011-11-09 20:10:18 -080039import com.google.android.gles_jni.EGLImpl;
Romain Guy2d614592010-06-09 18:21:37 -070040
41import javax.microedition.khronos.egl.EGL10;
42import javax.microedition.khronos.egl.EGL11;
43import javax.microedition.khronos.egl.EGLConfig;
44import javax.microedition.khronos.egl.EGLContext;
45import javax.microedition.khronos.egl.EGLDisplay;
46import javax.microedition.khronos.egl.EGLSurface;
Romain Guye3924992010-06-10 18:51:21 -070047import javax.microedition.khronos.opengles.GL;
Romain Guy2d614592010-06-09 18:21:37 -070048
Romain Guya9582652011-11-10 14:20:10 -080049import java.io.File;
Romain Guya676ad72012-02-13 17:47:10 -080050import java.io.PrintWriter;
Romain Guy77e67cf2012-06-19 16:38:50 -070051import java.util.concurrent.locks.ReentrantLock;
Romain Guya9582652011-11-10 14:20:10 -080052
Romain Guy484c7192011-07-25 11:56:33 -070053import static javax.microedition.khronos.egl.EGL10.*;
54
Romain Guy2d614592010-06-09 18:21:37 -070055/**
Romain Guy8d4aeb72013-02-12 16:08:55 -080056 * Interface for rendering a view hierarchy using hardware acceleration.
Romain Guy52036b12013-02-14 18:03:37 -080057 *
Romain Guy2d614592010-06-09 18:21:37 -070058 * @hide
59 */
Romain Guy61c8c9c2010-08-09 20:48:09 -070060public abstract class HardwareRenderer {
Romain Guy4f6aff32011-01-12 16:21:41 -080061 static final String LOG_TAG = "HardwareRenderer";
Romain Guyfb8b7632010-08-23 21:05:08 -070062
Romain Guy52339202010-09-03 16:04:46 -070063 /**
Romain Guya9582652011-11-10 14:20:10 -080064 * Name of the file that holds the shaders cache.
65 */
66 private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
67
68 /**
Romain Guy7d7b5492011-01-24 16:33:45 -080069 * Turn on to only refresh the parts of the screen that need updating.
Romain Guy069ea0e2011-02-08 12:24:52 -080070 * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
Romain Guy52036b12013-02-14 18:03:37 -080071 * must also have the value "true".
Romain Guy7d7b5492011-01-24 16:33:45 -080072 */
Romain Guy52036b12013-02-14 18:03:37 -080073 static final boolean RENDER_DIRTY_REGIONS = true;
Romain Guy7d7b5492011-01-24 16:33:45 -080074
75 /**
Romain Guy069ea0e2011-02-08 12:24:52 -080076 * System property used to enable or disable dirty regions invalidation.
77 * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
78 * The default value of this property is assumed to be true.
Igor Murashkina86ab6402013-08-30 12:58:36 -070079 *
Romain Guy069ea0e2011-02-08 12:24:52 -080080 * Possible values:
81 * "true", to enable partial invalidates
82 * "false", to disable partial invalidates
83 */
Romain Guy4b8c4f82012-04-27 15:48:35 -070084 static final String RENDER_DIRTY_REGIONS_PROPERTY = "debug.hwui.render_dirty_regions";
Romain Guy069ea0e2011-02-08 12:24:52 -080085
86 /**
Romain Guya676ad72012-02-13 17:47:10 -080087 * System property used to enable or disable hardware rendering profiling.
88 * The default value of this property is assumed to be false.
Chet Haase09280602012-04-03 16:15:34 -070089 *
Romain Guya676ad72012-02-13 17:47:10 -080090 * When profiling is enabled, the adb shell dumpsys gfxinfo command will
91 * output extra information about the time taken to execute by the last
92 * frames.
93 *
94 * Possible values:
95 * "true", to enable profiling
Romain Guy48ef4a92013-01-10 18:38:46 -080096 * "visual_bars", to enable profiling and visualize the results on screen
97 * "visual_lines", to enable profiling and visualize the results on screen
Romain Guya676ad72012-02-13 17:47:10 -080098 * "false", to disable profiling
Romain Guy672433d2013-01-04 19:05:13 -080099 *
Romain Guy48ef4a92013-01-10 18:38:46 -0800100 * @see #PROFILE_PROPERTY_VISUALIZE_BARS
101 * @see #PROFILE_PROPERTY_VISUALIZE_LINES
Romain Guya4fef022013-01-07 11:18:38 -0800102 *
Romain Guy4b8c4f82012-04-27 15:48:35 -0700103 * @hide
Romain Guya676ad72012-02-13 17:47:10 -0800104 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700105 public static final String PROFILE_PROPERTY = "debug.hwui.profile";
Romain Guya676ad72012-02-13 17:47:10 -0800106
107 /**
Romain Guya4fef022013-01-07 11:18:38 -0800108 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
Romain Guy48ef4a92013-01-10 18:38:46 -0800109 * value, profiling data will be visualized on screen as a bar chart.
Romain Guy672433d2013-01-04 19:05:13 -0800110 *
111 * @hide
112 */
Romain Guy48ef4a92013-01-10 18:38:46 -0800113 public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars";
114
115 /**
116 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
117 * value, profiling data will be visualized on screen as a line chart.
118 *
119 * @hide
120 */
121 public static final String PROFILE_PROPERTY_VISUALIZE_LINES = "visual_lines";
Romain Guy672433d2013-01-04 19:05:13 -0800122
123 /**
Chet Haase09280602012-04-03 16:15:34 -0700124 * System property used to specify the number of frames to be used
125 * when doing hardware rendering profiling.
126 * The default value of this property is #PROFILE_MAX_FRAMES.
127 *
128 * When profiling is enabled, the adb shell dumpsys gfxinfo command will
129 * output extra information about the time taken to execute by the last
130 * frames.
131 *
132 * Possible values:
133 * "60", to set the limit of frames to 60
134 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700135 static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes";
Chet Haase09280602012-04-03 16:15:34 -0700136
137 /**
Romain Guy484c7192011-07-25 11:56:33 -0700138 * System property used to debug EGL configuration choice.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700139 *
Romain Guy484c7192011-07-25 11:56:33 -0700140 * Possible values:
Romain Guy484c7192011-07-25 11:56:33 -0700141 * "choice", print the chosen configuration only
142 * "all", print all possible configurations
143 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700144 static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config";
Romain Guy484c7192011-07-25 11:56:33 -0700145
146 /**
Romain Guy7d7b5492011-01-24 16:33:45 -0800147 * Turn on to draw dirty regions every other frame.
Romain Guyb04f7e92012-02-15 12:36:54 -0800148 *
149 * Possible values:
150 * "true", to enable dirty regions debugging
151 * "false", to disable dirty regions debugging
Igor Murashkina86ab6402013-08-30 12:58:36 -0700152 *
Romain Guy4b8c4f82012-04-27 15:48:35 -0700153 * @hide
Romain Guy7d7b5492011-01-24 16:33:45 -0800154 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700155 public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions";
Romain Guy4ff0cf42012-08-06 14:51:10 -0700156
157 /**
158 * Turn on to flash hardware layers when they update.
159 *
160 * Possible values:
161 * "true", to enable hardware layers updates debugging
162 * "false", to disable hardware layers updates debugging
163 *
164 * @hide
165 */
166 public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY =
167 "debug.hwui.show_layers_updates";
168
Romain Guy7d7b5492011-01-24 16:33:45 -0800169 /**
Romain Guy78dd96d2013-05-03 14:24:16 -0700170 * Controls overdraw debugging.
Romain Guy7c450aa2012-09-21 19:15:00 -0700171 *
172 * Possible values:
Romain Guy7c450aa2012-09-21 19:15:00 -0700173 * "false", to disable overdraw debugging
Romain Guy78dd96d2013-05-03 14:24:16 -0700174 * "show", to show overdraw areas on screen
175 * "count", to display an overdraw counter
Romain Guy7c450aa2012-09-21 19:15:00 -0700176 *
177 * @hide
178 */
Romain Guy78dd96d2013-05-03 14:24:16 -0700179 public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw";
180
181 /**
182 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
183 * value, overdraw will be shown on screen by coloring pixels.
184 *
185 * @hide
186 */
187 public static final String OVERDRAW_PROPERTY_SHOW = "show";
188
189 /**
190 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
191 * value, an overdraw counter will be shown on screen.
192 *
193 * @hide
194 */
195 public static final String OVERDRAW_PROPERTY_COUNT = "count";
Romain Guy7c450aa2012-09-21 19:15:00 -0700196
197 /**
Romain Guy08bca882013-02-25 16:21:30 -0800198 * Turn on to debug non-rectangular clip operations.
199 *
200 * Possible values:
201 * "hide", to disable this debug mode
202 * "highlight", highlight drawing commands tested against a non-rectangular clip
203 * "stencil", renders the clip region on screen when set
204 *
205 * @hide
206 */
207 public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY =
208 "debug.hwui.show_non_rect_clip";
209
210 /**
Romain Guy52339202010-09-03 16:04:46 -0700211 * A process can set this flag to false to prevent the use of hardware
212 * rendering.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700213 *
Romain Guy52339202010-09-03 16:04:46 -0700214 * @hide
215 */
216 public static boolean sRendererDisabled = false;
217
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700218 /**
219 * Further hardware renderer disabling for the system process.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700220 *
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700221 * @hide
222 */
223 public static boolean sSystemRendererDisabled = false;
224
Romain Guya676ad72012-02-13 17:47:10 -0800225 /**
226 * Number of frames to profile.
227 */
Romain Guya21f8772012-05-07 10:20:52 -0700228 private static final int PROFILE_MAX_FRAMES = 128;
Romain Guya676ad72012-02-13 17:47:10 -0800229
230 /**
231 * Number of floats per profiled frame.
232 */
233 private static final int PROFILE_FRAME_DATA_COUNT = 3;
234
Romain Guy2d614592010-06-09 18:21:37 -0700235 private boolean mEnabled;
236 private boolean mRequested = true;
237
238 /**
Romain Guy67f27952010-12-07 20:09:23 -0800239 * Invoke this method to disable hardware rendering in the current process.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700240 *
Romain Guy52339202010-09-03 16:04:46 -0700241 * @hide
242 */
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700243 public static void disable(boolean system) {
Romain Guy52339202010-09-03 16:04:46 -0700244 sRendererDisabled = true;
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700245 if (system) {
246 sSystemRendererDisabled = true;
247 }
Romain Guy52339202010-09-03 16:04:46 -0700248 }
249
250 /**
Romain Guy61c8c9c2010-08-09 20:48:09 -0700251 * Indicates whether hardware acceleration is available under any form for
252 * the view hierarchy.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700253 *
Romain Guy61c8c9c2010-08-09 20:48:09 -0700254 * @return True if the view hierarchy can potentially be hardware accelerated,
255 * false otherwise
256 */
257 public static boolean isAvailable() {
258 return GLES20Canvas.isAvailable();
259 }
260
261 /**
Romain Guy2d614592010-06-09 18:21:37 -0700262 * Destroys the hardware rendering context.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700263 *
Romain Guy4caa4ed2010-08-25 14:46:24 -0700264 * @param full If true, destroys all associated resources.
Romain Guy2d614592010-06-09 18:21:37 -0700265 */
Romain Guy4caa4ed2010-08-25 14:46:24 -0700266 abstract void destroy(boolean full);
Romain Guy2d614592010-06-09 18:21:37 -0700267
268 /**
269 * Initializes the hardware renderer for the specified surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700270 *
Romain Guy786fc932012-07-24 16:24:56 -0700271 * @param surface The surface to hardware accelerate
Igor Murashkina86ab6402013-08-30 12:58:36 -0700272 *
Romain Guy2d614592010-06-09 18:21:37 -0700273 * @return True if the initialization was successful, false otherwise.
274 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700275 abstract boolean initialize(Surface surface) throws OutOfResourcesException;
276
Romain Guy2a83f002011-01-18 18:28:21 -0800277 /**
278 * Updates the hardware renderer for the specified surface.
Romain Guy786fc932012-07-24 16:24:56 -0700279 *
280 * @param surface The surface to hardware accelerate
Romain Guy2a83f002011-01-18 18:28:21 -0800281 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700282 abstract void updateSurface(Surface surface) throws OutOfResourcesException;
Romain Guy2d614592010-06-09 18:21:37 -0700283
284 /**
Romain Guy31f2c2e2011-11-21 10:55:41 -0800285 * Destroys the layers used by the specified view hierarchy.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700286 *
Romain Guy6d7475d2011-07-27 16:28:21 -0700287 * @param view The root of the view hierarchy
288 */
289 abstract void destroyLayers(View view);
290
291 /**
Romain Guy31f2c2e2011-11-21 10:55:41 -0800292 * Destroys all hardware rendering resources associated with the specified
293 * view hierarchy.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700294 *
Romain Guy31f2c2e2011-11-21 10:55:41 -0800295 * @param view The root of the view hierarchy
296 */
297 abstract void destroyHardwareResources(View view);
Igor Murashkina86ab6402013-08-30 12:58:36 -0700298
Romain Guy31f2c2e2011-11-21 10:55:41 -0800299 /**
Romain Guy03985752011-07-11 15:33:51 -0700300 * This method should be invoked whenever the current hardware renderer
Romain Guycf15efb2011-08-02 12:59:32 -0700301 * context should be reset.
Romain Guy786fc932012-07-24 16:24:56 -0700302 *
303 * @param surface The surface to hardware accelerate
Romain Guy7e1160e2011-07-08 15:49:50 -0700304 */
Romain Guy786fc932012-07-24 16:24:56 -0700305 abstract void invalidate(Surface surface);
Romain Guy03985752011-07-11 15:33:51 -0700306
307 /**
308 * This method should be invoked to ensure the hardware renderer is in
309 * valid state (for instance, to ensure the correct EGL context is bound
310 * to the current thread.)
Igor Murashkina86ab6402013-08-30 12:58:36 -0700311 *
Romain Guy03985752011-07-11 15:33:51 -0700312 * @return true if the renderer is now valid, false otherwise
313 */
314 abstract boolean validate();
Romain Guy7e1160e2011-07-08 15:49:50 -0700315
316 /**
Romain Guy1ac47652012-04-11 18:15:20 -0700317 * This method ensures the hardware renderer is in a valid state
318 * before executing the specified action.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700319 *
Romain Guy1ac47652012-04-11 18:15:20 -0700320 * This method will attempt to set a valid state even if the window
321 * the renderer is attached to was destroyed.
322 *
323 * @return true if the action was run
324 */
325 abstract boolean safelyRun(Runnable action);
326
327 /**
Romain Guy7e1160e2011-07-08 15:49:50 -0700328 * Setup the hardware renderer for drawing. This is called whenever the
329 * size of the target surface changes or when the surface is first created.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700330 *
Romain Guy2d614592010-06-09 18:21:37 -0700331 * @param width Width of the drawing surface.
332 * @param height Height of the drawing surface.
Romain Guy2d614592010-06-09 18:21:37 -0700333 */
Romain Guyfb8b7632010-08-23 21:05:08 -0700334 abstract void setup(int width, int height);
Romain Guy2d614592010-06-09 18:21:37 -0700335
Romain Guy069ea0e2011-02-08 12:24:52 -0800336 /**
Chet Haase40e03832011-10-06 08:34:13 -0700337 * Gets the current width of the surface. This is the width that the surface
338 * was last set to in a call to {@link #setup(int, int)}.
339 *
340 * @return the current width of the surface
341 */
342 abstract int getWidth();
343
344 /**
345 * Gets the current height of the surface. This is the height that the surface
346 * was last set to in a call to {@link #setup(int, int)}.
347 *
348 * @return the current width of the surface
349 */
350 abstract int getHeight();
351
352 /**
Chet Haase08837c22011-11-28 11:53:21 -0800353 * Gets the current canvas associated with this HardwareRenderer.
354 *
355 * @return the current HardwareCanvas
356 */
357 abstract HardwareCanvas getCanvas();
358
359 /**
Romain Guya676ad72012-02-13 17:47:10 -0800360 * Outputs extra debugging information in the specified file descriptor.
361 * @param pw
362 */
363 abstract void dumpGfxInfo(PrintWriter pw);
Michael Jurkaa3fabff2012-03-28 17:22:29 +0200364
365 /**
366 * Outputs the total number of frames rendered (used for fps calculations)
367 *
368 * @return the number of frames rendered
369 */
370 abstract long getFrameCount();
371
Romain Guya676ad72012-02-13 17:47:10 -0800372 /**
Romain Guy5bb3c732012-11-29 17:52:58 -0800373 * Loads system properties used by the renderer. This method is invoked
374 * whenever system properties are modified. Implementations can use this
375 * to trigger live updates of the renderer based on properties.
376 *
377 * @param surface The surface to update with the new properties.
378 * Can be null.
379 *
380 * @return True if a property has changed.
381 */
382 abstract boolean loadSystemProperties(Surface surface);
383
384 private static native boolean nLoadProperties();
385
386 /**
Romain Guya9582652011-11-10 14:20:10 -0800387 * Sets the directory to use as a persistent storage for hardware rendering
388 * resources.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700389 *
Romain Guya9582652011-11-10 14:20:10 -0800390 * @param cacheDir A directory the current process can write to
Romain Guy52036b12013-02-14 18:03:37 -0800391 *
392 * @hide
Romain Guya9582652011-11-10 14:20:10 -0800393 */
394 public static void setupDiskCache(File cacheDir) {
395 nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
396 }
397
398 private static native void nSetupShadersDiskCache(String cacheFile);
399
400 /**
Jamie Gennisb335fad2012-01-15 18:54:57 -0800401 * Notifies EGL that the frame is about to be rendered.
Romain Guy76878822012-03-30 14:54:22 -0700402 * @param size
Jamie Gennisb335fad2012-01-15 18:54:57 -0800403 */
Romain Guy672433d2013-01-04 19:05:13 -0800404 static void beginFrame(int[] size) {
Romain Guy76878822012-03-30 14:54:22 -0700405 nBeginFrame(size);
Jamie Gennisb335fad2012-01-15 18:54:57 -0800406 }
407
Romain Guy76878822012-03-30 14:54:22 -0700408 private static native void nBeginFrame(int[] size);
Jamie Gennisb335fad2012-01-15 18:54:57 -0800409
410 /**
Romain Guye9bc11f2013-05-23 12:47:26 -0700411 * Returns the current system time according to the renderer.
412 * This method is used for debugging only and should not be used
413 * as a clock.
414 */
415 static long getSystemTime() {
416 return nGetSystemTime();
417 }
418
419 private static native long nGetSystemTime();
420
421 /**
Romain Guy244ada12012-03-28 16:41:26 -0700422 * Preserves the back buffer of the current surface after a buffer swap.
423 * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
424 * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
425 * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
426 *
427 * @return True if the swap behavior was successfully changed,
428 * false otherwise.
429 */
430 static boolean preserveBackBuffer() {
431 return nPreserveBackBuffer();
432 }
433
434 private static native boolean nPreserveBackBuffer();
435
436 /**
437 * Indicates whether the current surface preserves its back buffer
438 * after a buffer swap.
439 *
440 * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
441 * false otherwise
442 */
443 static boolean isBackBufferPreserved() {
444 return nIsBackBufferPreserved();
445 }
446
447 private static native boolean nIsBackBufferPreserved();
448
449 /**
Romain Guy11cb6422012-09-21 00:39:43 -0700450 * Indicates that the specified hardware layer needs to be updated
451 * as soon as possible.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700452 *
Romain Guy11cb6422012-09-21 00:39:43 -0700453 * @param layer The hardware layer that needs an update
Romain Guy40543602013-06-12 15:31:28 -0700454 *
455 * @see #flushLayerUpdates()
Romain Guye93482f2013-06-17 13:14:51 -0700456 * @see #cancelLayerUpdate(HardwareLayer)
Romain Guy11cb6422012-09-21 00:39:43 -0700457 */
458 abstract void pushLayerUpdate(HardwareLayer layer);
459
460 /**
Romain Guye93482f2013-06-17 13:14:51 -0700461 * Cancels a queued layer update. If the specified layer was not
462 * queued for update, this method has no effect.
463 *
464 * @param layer The layer whose update to cancel
465 *
466 * @see #pushLayerUpdate(HardwareLayer)
467 */
468 abstract void cancelLayerUpdate(HardwareLayer layer);
469
470 /**
Romain Guy40543602013-06-12 15:31:28 -0700471 * Forces all enqueued layer updates to be executed immediately.
472 *
473 * @see #pushLayerUpdate(HardwareLayer)
474 */
475 abstract void flushLayerUpdates();
476
477 /**
Romain Guy069ea0e2011-02-08 12:24:52 -0800478 * Interface used to receive callbacks whenever a view is drawn by
479 * a hardware renderer instance.
480 */
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800481 interface HardwareDrawCallbacks {
Romain Guy069ea0e2011-02-08 12:24:52 -0800482 /**
483 * Invoked before a view is drawn by a hardware renderer.
Romain Guy96885eb2013-03-26 15:05:58 -0700484 * This method can be used to apply transformations to the
485 * canvas but no drawing command should be issued.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700486 *
Romain Guy069ea0e2011-02-08 12:24:52 -0800487 * @param canvas The Canvas used to render the view.
488 */
Romain Guy7d70fbf2011-05-24 17:40:25 -0700489 void onHardwarePreDraw(HardwareCanvas canvas);
Romain Guy069ea0e2011-02-08 12:24:52 -0800490
491 /**
492 * Invoked after a view is drawn by a hardware renderer.
Romain Guy96885eb2013-03-26 15:05:58 -0700493 * It is safe to invoke drawing commands from this method.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700494 *
Romain Guy069ea0e2011-02-08 12:24:52 -0800495 * @param canvas The Canvas used to render the view.
496 */
Romain Guy7d70fbf2011-05-24 17:40:25 -0700497 void onHardwarePostDraw(HardwareCanvas canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800498 }
499
Romain Guy2d614592010-06-09 18:21:37 -0700500 /**
501 * Draws the specified view.
Romain Guy7d7b5492011-01-24 16:33:45 -0800502 *
Romain Guy2d614592010-06-09 18:21:37 -0700503 * @param view The view to draw.
504 * @param attachInfo AttachInfo tied to the specified view.
Romain Guy7d7b5492011-01-24 16:33:45 -0800505 * @param callbacks Callbacks invoked when drawing happens.
506 * @param dirty The dirty rectangle to update, can be null.
Romain Guy2d614592010-06-09 18:21:37 -0700507 */
Romain Guye55945e2013-04-04 15:26:04 -0700508 abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Romain Guy7d7b5492011-01-24 16:33:45 -0800509 Rect dirty);
Romain Guy2d614592010-06-09 18:21:37 -0700510
511 /**
Romain Guy53ca03d2010-10-08 18:55:27 -0700512 * Creates a new display list that can be used to record batches of
513 * drawing operations.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700514 *
Romain Guy52036b12013-02-14 18:03:37 -0800515 * @param name The name of the display list, used for debugging purpose. May be null.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700516 *
Romain Guy53ca03d2010-10-08 18:55:27 -0700517 * @return A new display list.
Romain Guy52036b12013-02-14 18:03:37 -0800518 *
519 * @hide
Romain Guyb051e892010-09-28 19:09:36 -0700520 */
Romain Guy13631f32012-01-30 17:41:55 -0800521 public abstract DisplayList createDisplayList(String name);
Romain Guyb051e892010-09-28 19:09:36 -0700522
523 /**
Romain Guyaa6c24c2011-04-28 18:40:04 -0700524 * Creates a new hardware layer. A hardware layer built by calling this
525 * method will be treated as a texture layer, instead of as a render target.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700526 *
Romain Guya9489272011-06-22 20:58:11 -0700527 * @param isOpaque Whether the layer should be opaque or not
Igor Murashkina86ab6402013-08-30 12:58:36 -0700528 *
Romain Guyaa6c24c2011-04-28 18:40:04 -0700529 * @return A hardware layer
Jamie Gennis2af35242012-04-05 11:44:30 -0700530 */
Romain Guya9489272011-06-22 20:58:11 -0700531 abstract HardwareLayer createHardwareLayer(boolean isOpaque);
Jamie Gennis2af35242012-04-05 11:44:30 -0700532
Romain Guyaa6c24c2011-04-28 18:40:04 -0700533 /**
Romain Guy6c319ca2011-01-11 14:29:25 -0800534 * Creates a new hardware layer.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700535 *
Romain Guy6c319ca2011-01-11 14:29:25 -0800536 * @param width The minimum width of the layer
537 * @param height The minimum height of the layer
538 * @param isOpaque Whether the layer should be opaque or not
Igor Murashkina86ab6402013-08-30 12:58:36 -0700539 *
Romain Guy6c319ca2011-01-11 14:29:25 -0800540 * @return A hardware layer
541 */
542 abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700543
544 /**
545 * Creates a new {@link SurfaceTexture} that can be used to render into the
546 * specified hardware layer.
Romain Guyaa6c24c2011-04-28 18:40:04 -0700547 *
548 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
Igor Murashkina86ab6402013-08-30 12:58:36 -0700549 *
Romain Guyaa6c24c2011-04-28 18:40:04 -0700550 * @return A {@link SurfaceTexture}
551 */
Romain Guye5e0c502011-06-15 15:18:31 -0700552 abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700553
554 /**
Jamie Gennis2af35242012-04-05 11:44:30 -0700555 * Sets the {@link android.graphics.SurfaceTexture} that will be used to
556 * render into the specified hardware layer.
557 *
558 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
559 * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer
560 */
561 abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture);
562
563 /**
Romain Guyba6be8a2012-04-23 18:22:09 -0700564 * Detaches the specified functor from the current functor execution queue.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700565 *
Romain Guyba6be8a2012-04-23 18:22:09 -0700566 * @param functor The native functor to remove from the execution queue.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700567 *
568 * @see HardwareCanvas#callDrawGLFunction(int)
569 * @see #attachFunctor(android.view.View.AttachInfo, int)
Romain Guyba6be8a2012-04-23 18:22:09 -0700570 */
Ashok Bhata0398432014-01-20 20:08:01 +0000571 abstract void detachFunctor(long functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700572
573 /**
574 * Schedules the specified functor in the functors execution queue.
575 *
576 * @param attachInfo AttachInfo tied to this renderer.
577 * @param functor The native functor to insert in the execution queue.
578 *
579 * @see HardwareCanvas#callDrawGLFunction(int)
Chris Craik41ee4652012-05-31 15:05:57 -0700580 * @see #detachFunctor(int)
581 *
582 * @return true if the functor was attached successfully
Romain Guyba6be8a2012-04-23 18:22:09 -0700583 */
Ashok Bhata0398432014-01-20 20:08:01 +0000584 abstract boolean attachFunctor(View.AttachInfo attachInfo, long functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700585
586 /**
Romain Guy2d614592010-06-09 18:21:37 -0700587 * Initializes the hardware renderer for the specified surface and setup the
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700588 * renderer for drawing, if needed. This is invoked when the ViewAncestor has
Romain Guy2d614592010-06-09 18:21:37 -0700589 * potentially lost the hardware renderer. The hardware renderer should be
590 * reinitialized and setup when the render {@link #isRequested()} and
591 * {@link #isEnabled()}.
Romain Guy44d79742012-01-13 12:12:09 -0800592 *
Romain Guy2d614592010-06-09 18:21:37 -0700593 * @param width The width of the drawing surface.
594 * @param height The height of the drawing surface.
Romain Guy786fc932012-07-24 16:24:56 -0700595 * @param surface The surface to hardware accelerate
Igor Murashkina86ab6402013-08-30 12:58:36 -0700596 *
Romain Guydfab3632012-10-03 14:53:25 -0700597 * @return true if the surface was initialized, false otherwise. Returning
598 * false might mean that the surface was already initialized.
Romain Guy2d614592010-06-09 18:21:37 -0700599 */
Romain Guydfab3632012-10-03 14:53:25 -0700600 boolean initializeIfNeeded(int width, int height, Surface surface)
Igor Murashkina86ab6402013-08-30 12:58:36 -0700601 throws OutOfResourcesException {
Romain Guy2d614592010-06-09 18:21:37 -0700602 if (isRequested()) {
603 // We lost the gl context, so recreate it.
604 if (!isEnabled()) {
Romain Guy786fc932012-07-24 16:24:56 -0700605 if (initialize(surface)) {
Romain Guyfb8b7632010-08-23 21:05:08 -0700606 setup(width, height);
Romain Guydfab3632012-10-03 14:53:25 -0700607 return true;
Romain Guy2d614592010-06-09 18:21:37 -0700608 }
609 }
Romain Guydfab3632012-10-03 14:53:25 -0700610 }
611 return false;
Romain Guy2d614592010-06-09 18:21:37 -0700612 }
613
614 /**
Romain Guyef359272013-01-31 19:07:29 -0800615 * Optional, sets the name of the renderer. Useful for debugging purposes.
616 *
617 * @param name The name of this renderer, can be null
618 */
619 abstract void setName(String name);
620
621 /**
Romain Guy2d614592010-06-09 18:21:37 -0700622 * Creates a hardware renderer using OpenGL.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700623 *
Romain Guy2d614592010-06-09 18:21:37 -0700624 * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.)
Romain Guye4d01122010-06-16 18:44:05 -0700625 * @param translucent True if the surface is translucent, false otherwise
Igor Murashkina86ab6402013-08-30 12:58:36 -0700626 *
Romain Guy2d614592010-06-09 18:21:37 -0700627 * @return A hardware renderer backed by OpenGL.
628 */
Romain Guye4d01122010-06-16 18:44:05 -0700629 static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
Romain Guy2d614592010-06-09 18:21:37 -0700630 switch (glVersion) {
Romain Guye3924992010-06-10 18:51:21 -0700631 case 2:
Romain Guy16393512010-08-08 00:14:31 -0700632 return Gl20Renderer.create(translucent);
Romain Guy2d614592010-06-09 18:21:37 -0700633 }
634 throw new IllegalArgumentException("Unknown GL version: " + glVersion);
635 }
636
637 /**
Romain Guybdf76092011-07-18 15:00:43 -0700638 * Invoke this method when the system is running out of memory. This
639 * method will attempt to recover as much memory as possible, based on
640 * the specified hint.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700641 *
Romain Guybdf76092011-07-18 15:00:43 -0700642 * @param level Hint about the amount of memory that should be trimmed,
643 * see {@link android.content.ComponentCallbacks}
644 */
645 static void trimMemory(int level) {
Romain Guy19f86e82012-04-23 15:19:07 -0700646 startTrimMemory(level);
647 endTrimMemory();
648 }
649
650 /**
651 * Starts the process of trimming memory. Usually this call will setup
652 * hardware rendering context and reclaim memory.Extra cleanup might
653 * be required by calling {@link #endTrimMemory()}.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700654 *
Romain Guy19f86e82012-04-23 15:19:07 -0700655 * @param level Hint about the amount of memory that should be trimmed,
656 * see {@link android.content.ComponentCallbacks}
657 */
658 static void startTrimMemory(int level) {
659 Gl20Renderer.startTrimMemory(level);
660 }
661
662 /**
663 * Finishes the process of trimming memory. This method will usually
664 * cleanup special resources used by the memory trimming process.
665 */
666 static void endTrimMemory() {
667 Gl20Renderer.endTrimMemory();
Romain Guybdf76092011-07-18 15:00:43 -0700668 }
669
670 /**
Romain Guy2d614592010-06-09 18:21:37 -0700671 * Indicates whether hardware acceleration is currently enabled.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700672 *
Romain Guy2d614592010-06-09 18:21:37 -0700673 * @return True if hardware acceleration is in use, false otherwise.
674 */
675 boolean isEnabled() {
676 return mEnabled;
677 }
678
679 /**
680 * Indicates whether hardware acceleration is currently enabled.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700681 *
Romain Guy2d614592010-06-09 18:21:37 -0700682 * @param enabled True if the hardware renderer is in use, false otherwise.
683 */
684 void setEnabled(boolean enabled) {
685 mEnabled = enabled;
686 }
687
688 /**
689 * Indicates whether hardware acceleration is currently request but not
690 * necessarily enabled yet.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700691 *
Romain Guy2d614592010-06-09 18:21:37 -0700692 * @return True if requested, false otherwise.
693 */
694 boolean isRequested() {
695 return mRequested;
696 }
697
698 /**
Romain Guy9745fae2010-12-08 11:39:15 -0800699 * Indicates whether hardware acceleration is currently requested but not
Romain Guy2d614592010-06-09 18:21:37 -0700700 * necessarily enabled yet.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700701 *
Romain Guy2d614592010-06-09 18:21:37 -0700702 * @return True to request hardware acceleration, false otherwise.
703 */
704 void setRequested(boolean requested) {
705 mRequested = requested;
706 }
707
Romain Guy48ef4a92013-01-10 18:38:46 -0800708 /**
709 * Describes a series of frames that should be drawn on screen as a graph.
710 * Each frame is composed of 1 or more elements.
711 */
712 abstract class GraphDataProvider {
713 /**
714 * Draws the graph as bars. Frame elements are stacked on top of
715 * each other.
716 */
717 public static final int GRAPH_TYPE_BARS = 0;
718 /**
719 * Draws the graph as lines. The number of series drawn corresponds
720 * to the number of elements.
721 */
722 public static final int GRAPH_TYPE_LINES = 1;
723
724 /**
725 * Returns the type of graph to render.
726 *
727 * @return {@link #GRAPH_TYPE_BARS} or {@link #GRAPH_TYPE_LINES}
728 */
729 abstract int getGraphType();
730
731 /**
732 * This method is invoked before the graph is drawn. This method
733 * can be used to compute sizes, etc.
734 *
735 * @param metrics The display metrics
736 */
737 abstract void prepare(DisplayMetrics metrics);
738
739 /**
740 * @return The size in pixels of a vertical unit.
741 */
742 abstract int getVerticalUnitSize();
743
744 /**
745 * @return The size in pixels of a horizontal unit.
746 */
747 abstract int getHorizontalUnitSize();
748
749 /**
750 * @return The size in pixels of the margin between horizontal units.
751 */
752 abstract int getHorizontaUnitMargin();
753
754 /**
755 * An optional threshold value.
756 *
757 * @return A value >= 0 to draw the threshold, a negative value
758 * to ignore it.
759 */
760 abstract float getThreshold();
761
762 /**
763 * The data to draw in the graph. The number of elements in the
764 * array must be at least {@link #getFrameCount()} * {@link #getElementCount()}.
765 * If a value is negative the following values will be ignored.
766 */
767 abstract float[] getData();
768
769 /**
770 * Returns the number of frames to render in the graph.
771 */
772 abstract int getFrameCount();
773
774 /**
775 * Returns the number of elements in each frame. This directly affects
776 * the number of series drawn in the graph.
777 */
778 abstract int getElementCount();
779
780 /**
781 * Returns the current frame, if any. If the returned value is negative
782 * the current frame is ignored.
783 */
784 abstract int getCurrentFrame();
785
786 /**
787 * Prepares the paint to draw the specified element (or series.)
788 */
789 abstract void setupGraphPaint(Paint paint, int elementIndex);
790
791 /**
792 * Prepares the paint to draw the threshold.
793 */
794 abstract void setupThresholdPaint(Paint paint);
795
796 /**
797 * Prepares the paint to draw the current frame indicator.
798 */
799 abstract void setupCurrentFramePaint(Paint paint);
800 }
801
Romain Guy2d614592010-06-09 18:21:37 -0700802 @SuppressWarnings({"deprecation"})
Romain Guye3924992010-06-10 18:51:21 -0700803 static abstract class GlRenderer extends HardwareRenderer {
Romain Guy16260e72011-09-01 14:26:11 -0700804 static final int SURFACE_STATE_ERROR = 0;
805 static final int SURFACE_STATE_SUCCESS = 1;
806 static final int SURFACE_STATE_UPDATED = 2;
Romain Guy8f3b8e32012-03-27 16:33:45 -0700807
Chris Craik65924a32012-04-05 17:52:11 -0700808 static final int FUNCTOR_PROCESS_DELAY = 4;
Romain Guy8f3b8e32012-03-27 16:33:45 -0700809
Romain Guy48ef4a92013-01-10 18:38:46 -0800810 private static final int PROFILE_DRAW_MARGIN = 0;
811 private static final int PROFILE_DRAW_WIDTH = 3;
812 private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
813 private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
814 private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
815 private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
816 private static final int PROFILE_DRAW_DP_PER_MS = 7;
817
Romain Guy78dd96d2013-05-03 14:24:16 -0700818 private static final String[] VISUALIZERS = {
819 PROFILE_PROPERTY_VISUALIZE_BARS,
820 PROFILE_PROPERTY_VISUALIZE_LINES
821 };
822
823 private static final String[] OVERDRAW = {
824 OVERDRAW_PROPERTY_SHOW,
825 OVERDRAW_PROPERTY_COUNT
826 };
827 private static final int OVERDRAW_TYPE_COUNT = 1;
828
Romain Guyfb8b7632010-08-23 21:05:08 -0700829 static EGL10 sEgl;
830 static EGLDisplay sEglDisplay;
831 static EGLConfig sEglConfig;
Romain Guy566b3ef2011-07-18 18:38:12 -0700832 static final Object[] sEglLock = new Object[0];
Chet Haase40e03832011-10-06 08:34:13 -0700833 int mWidth = -1, mHeight = -1;
Romain Guy2d614592010-06-09 18:21:37 -0700834
Romain Guy5d6999e2012-03-22 19:15:04 -0700835 static final ThreadLocal<ManagedEGLContext> sEglContextStorage
836 = new ThreadLocal<ManagedEGLContext>();
Romain Guy566b3ef2011-07-18 18:38:12 -0700837
838 EGLContext mEglContext;
839 Thread mEglThread;
Romain Guyfb8b7632010-08-23 21:05:08 -0700840
841 EGLSurface mEglSurface;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700842
Romain Guye3924992010-06-10 18:51:21 -0700843 GL mGl;
Romain Guy67f27952010-12-07 20:09:23 -0800844 HardwareCanvas mCanvas;
Romain Guya676ad72012-02-13 17:47:10 -0800845
Romain Guyef359272013-01-31 19:07:29 -0800846 String mName;
847
Michael Jurkaa3fabff2012-03-28 17:22:29 +0200848 long mFrameCount;
Romain Guy7d7b5492011-01-24 16:33:45 -0800849 Paint mDebugPaint;
850
Romain Guy7e1160e2011-07-08 15:49:50 -0700851 static boolean sDirtyRegions;
852 static final boolean sDirtyRegionsRequested;
853 static {
854 String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
855 //noinspection PointlessBooleanExpression,ConstantConditions
856 sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
857 sDirtyRegionsRequested = sDirtyRegions;
858 }
859
860 boolean mDirtyRegionsEnabled;
Romain Guy9477c6e2011-12-09 12:27:21 -0800861 boolean mUpdateDirtyRegions;
862
Romain Guy5bb3c732012-11-29 17:52:58 -0800863 boolean mProfileEnabled;
Romain Guy48ef4a92013-01-10 18:38:46 -0800864 int mProfileVisualizerType = -1;
Romain Guy5bb3c732012-11-29 17:52:58 -0800865 float[] mProfileData;
866 ReentrantLock mProfileLock;
Romain Guya676ad72012-02-13 17:47:10 -0800867 int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
Romain Guy672433d2013-01-04 19:05:13 -0800868
Romain Guy48ef4a92013-01-10 18:38:46 -0800869 GraphDataProvider mDebugDataProvider;
870 float[][] mProfileShapes;
Romain Guy672433d2013-01-04 19:05:13 -0800871 Paint mProfilePaint;
872
Romain Guy5bb3c732012-11-29 17:52:58 -0800873 boolean mDebugDirtyRegions;
Romain Guy78dd96d2013-05-03 14:24:16 -0700874 int mDebugOverdraw = -1;
875 HardwareLayer mDebugOverdrawLayer;
876 Paint mDebugOverdrawPaint;
Romain Guya676ad72012-02-13 17:47:10 -0800877
Romain Guye4d01122010-06-16 18:44:05 -0700878 final int mGlVersion;
879 final boolean mTranslucent;
Romain Guye3924992010-06-10 18:51:21 -0700880
Romain Guyfb8b7632010-08-23 21:05:08 -0700881 private boolean mDestroyed;
Romain Guy566b3ef2011-07-18 18:38:12 -0700882
Romain Guycabfcc12011-03-07 18:06:46 -0800883 private final Rect mRedrawClip = new Rect();
Romain Guy8f3b8e32012-03-27 16:33:45 -0700884
Romain Guy76878822012-03-30 14:54:22 -0700885 private final int[] mSurfaceSize = new int[2];
Romain Guy8f3b8e32012-03-27 16:33:45 -0700886 private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
Romain Guyfb8b7632010-08-23 21:05:08 -0700887
Romain Guye9bc11f2013-05-23 12:47:26 -0700888 private long mDrawDelta = Long.MAX_VALUE;
889
Romain Guye4d01122010-06-16 18:44:05 -0700890 GlRenderer(int glVersion, boolean translucent) {
Romain Guye3924992010-06-10 18:51:21 -0700891 mGlVersion = glVersion;
Romain Guye4d01122010-06-16 18:44:05 -0700892 mTranslucent = translucent;
Romain Guy9ace8f52011-07-07 20:50:11 -0700893
Romain Guy5bb3c732012-11-29 17:52:58 -0800894 loadSystemProperties(null);
895 }
Romain Guya676ad72012-02-13 17:47:10 -0800896
Romain Guy5bb3c732012-11-29 17:52:58 -0800897 @Override
898 boolean loadSystemProperties(Surface surface) {
Romain Guya4fef022013-01-07 11:18:38 -0800899 boolean value;
Romain Guy5bb3c732012-11-29 17:52:58 -0800900 boolean changed = false;
901
Romain Guya4fef022013-01-07 11:18:38 -0800902 String profiling = SystemProperties.get(PROFILE_PROPERTY);
Romain Guy78dd96d2013-05-03 14:24:16 -0700903 int graphType = search(VISUALIZERS, profiling);
Romain Guy48ef4a92013-01-10 18:38:46 -0800904 value = graphType >= 0;
Romain Guya4fef022013-01-07 11:18:38 -0800905
Romain Guy48ef4a92013-01-10 18:38:46 -0800906 if (graphType != mProfileVisualizerType) {
Romain Guya4fef022013-01-07 11:18:38 -0800907 changed = true;
Romain Guy48ef4a92013-01-10 18:38:46 -0800908 mProfileVisualizerType = graphType;
Romain Guya4fef022013-01-07 11:18:38 -0800909
Romain Guy48ef4a92013-01-10 18:38:46 -0800910 mProfileShapes = null;
Romain Guya4fef022013-01-07 11:18:38 -0800911 mProfilePaint = null;
Romain Guy48ef4a92013-01-10 18:38:46 -0800912
913 if (value) {
914 mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
915 } else {
916 mDebugDataProvider = null;
917 }
Romain Guya4fef022013-01-07 11:18:38 -0800918 }
919
920 // If on-screen profiling is not enabled, we need to check whether
921 // console profiling only is enabled
922 if (!value) {
923 value = Boolean.parseBoolean(profiling);
924 }
925
Romain Guy5bb3c732012-11-29 17:52:58 -0800926 if (value != mProfileEnabled) {
927 changed = true;
928 mProfileEnabled = value;
929
930 if (mProfileEnabled) {
931 Log.d(LOG_TAG, "Profiling hardware renderer");
Romain Guy77e67cf2012-06-19 16:38:50 -0700932
Romain Guy5bb3c732012-11-29 17:52:58 -0800933 int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY,
934 PROFILE_MAX_FRAMES);
935 mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
936 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
937 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
938 }
939
940 mProfileLock = new ReentrantLock();
941 } else {
942 mProfileData = null;
943 mProfileLock = null;
Romain Guy48ef4a92013-01-10 18:38:46 -0800944 mProfileVisualizerType = -1;
Romain Guy5bb3c732012-11-29 17:52:58 -0800945 }
Romain Guy672433d2013-01-04 19:05:13 -0800946
Romain Guy666d5da2013-01-07 11:29:14 -0800947 mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
Romain Guy672433d2013-01-04 19:05:13 -0800948 }
949
Romain Guy5bb3c732012-11-29 17:52:58 -0800950 value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
951 if (value != mDebugDirtyRegions) {
952 changed = true;
953 mDebugDirtyRegions = value;
954
955 if (mDebugDirtyRegions) {
956 Log.d(LOG_TAG, "Debugging dirty regions");
957 }
Romain Guyb04f7e92012-02-15 12:36:54 -0800958 }
Romain Guy7c450aa2012-09-21 19:15:00 -0700959
Romain Guy78dd96d2013-05-03 14:24:16 -0700960 String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY);
961 int debugOverdraw = search(OVERDRAW, overdraw);
962 if (debugOverdraw != mDebugOverdraw) {
Romain Guy5bb3c732012-11-29 17:52:58 -0800963 changed = true;
Romain Guy78dd96d2013-05-03 14:24:16 -0700964 mDebugOverdraw = debugOverdraw;
965
966 if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
967 if (mDebugOverdrawLayer != null) {
968 mDebugOverdrawLayer.destroy();
969 mDebugOverdrawLayer = null;
970 mDebugOverdrawPaint = null;
971 }
972 }
Romain Guy5bb3c732012-11-29 17:52:58 -0800973 }
974
975 if (nLoadProperties()) {
976 changed = true;
977 }
978
979 return changed;
Romain Guya676ad72012-02-13 17:47:10 -0800980 }
981
Romain Guy78dd96d2013-05-03 14:24:16 -0700982 private static int search(String[] values, String value) {
983 for (int i = 0; i < values.length; i++) {
984 if (values[i].equals(value)) return i;
985 }
986 return -1;
987 }
988
Romain Guya676ad72012-02-13 17:47:10 -0800989 @Override
990 void dumpGfxInfo(PrintWriter pw) {
991 if (mProfileEnabled) {
992 pw.printf("\n\tDraw\tProcess\tExecute\n");
Romain Guy77e67cf2012-06-19 16:38:50 -0700993
994 mProfileLock.lock();
995 try {
996 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
997 if (mProfileData[i] < 0) {
998 break;
999 }
1000 pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
1001 mProfileData[i + 2]);
1002 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
Chet Haase09280602012-04-03 16:15:34 -07001003 }
Romain Guy77e67cf2012-06-19 16:38:50 -07001004 mProfileCurrentFrame = mProfileData.length;
1005 } finally {
1006 mProfileLock.unlock();
Romain Guya676ad72012-02-13 17:47:10 -08001007 }
1008 }
Romain Guy2d614592010-06-09 18:21:37 -07001009 }
1010
Michael Jurkaa3fabff2012-03-28 17:22:29 +02001011 @Override
1012 long getFrameCount() {
1013 return mFrameCount;
1014 }
1015
Romain Guye3924992010-06-10 18:51:21 -07001016 /**
Romain Guy02ccac62011-06-24 13:20:23 -07001017 * Indicates whether this renderer instance can track and update dirty regions.
1018 */
1019 boolean hasDirtyRegions() {
Romain Guy7e1160e2011-07-08 15:49:50 -07001020 return mDirtyRegionsEnabled;
Romain Guy02ccac62011-06-24 13:20:23 -07001021 }
1022
1023 /**
Romain Guy4caa4ed2010-08-25 14:46:24 -07001024 * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
Romain Guye3924992010-06-10 18:51:21 -07001025 * is invoked and the requested flag is turned off. The error code is
1026 * also logged as a warning.
1027 */
Romain Guyb025b9c2010-09-16 14:16:48 -07001028 void checkEglErrors() {
Romain Guy2d614592010-06-09 18:21:37 -07001029 if (isEnabled()) {
Romain Guy740ee652012-09-17 18:11:40 -07001030 checkEglErrorsForced();
1031 }
1032 }
1033
1034 private void checkEglErrorsForced() {
1035 int error = sEgl.eglGetError();
1036 if (error != EGL_SUCCESS) {
1037 // something bad has happened revert to
1038 // normal rendering.
1039 Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
1040 fallback(error != EGL11.EGL_CONTEXT_LOST);
Romain Guy2d614592010-06-09 18:21:37 -07001041 }
1042 }
Romain Guy67f27952010-12-07 20:09:23 -08001043
Romain Guy9745fae2010-12-08 11:39:15 -08001044 private void fallback(boolean fallback) {
1045 destroy(true);
1046 if (fallback) {
1047 // we'll try again if it was context lost
1048 setRequested(false);
Romain Guy3b748a42013-04-17 18:54:38 -07001049 Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
Romain Guy9745fae2010-12-08 11:39:15 -08001050 + "Switching back to software rendering.");
1051 }
1052 }
1053
Romain Guy2d614592010-06-09 18:21:37 -07001054 @Override
Igor Murashkina86ab6402013-08-30 12:58:36 -07001055 boolean initialize(Surface surface) throws OutOfResourcesException {
Romain Guy2d614592010-06-09 18:21:37 -07001056 if (isRequested() && !isEnabled()) {
Romain Guy3b748a42013-04-17 18:54:38 -07001057 boolean contextCreated = initializeEgl();
Romain Guy786fc932012-07-24 16:24:56 -07001058 mGl = createEglSurface(surface);
Romain Guyfb8b7632010-08-23 21:05:08 -07001059 mDestroyed = false;
Romain Guye3924992010-06-10 18:51:21 -07001060
1061 if (mGl != null) {
Romain Guyfb8b7632010-08-23 21:05:08 -07001062 int err = sEgl.eglGetError();
Romain Guy484c7192011-07-25 11:56:33 -07001063 if (err != EGL_SUCCESS) {
Romain Guy4caa4ed2010-08-25 14:46:24 -07001064 destroy(true);
Romain Guye3924992010-06-10 18:51:21 -07001065 setRequested(false);
1066 } else {
Romain Guy4caa4ed2010-08-25 14:46:24 -07001067 if (mCanvas == null) {
1068 mCanvas = createCanvas();
Romain Guyef359272013-01-31 19:07:29 -08001069 mCanvas.setName(mName);
Romain Guyfb8b7632010-08-23 21:05:08 -07001070 }
Romain Guye55945e2013-04-04 15:26:04 -07001071 setEnabled(true);
Romain Guy3b748a42013-04-17 18:54:38 -07001072
1073 if (contextCreated) {
1074 initAtlas();
1075 }
Romain Guye3924992010-06-10 18:51:21 -07001076 }
1077
1078 return mCanvas != null;
1079 }
Romain Guy2d614592010-06-09 18:21:37 -07001080 }
1081 return false;
1082 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001083
Romain Guy2a83f002011-01-18 18:28:21 -08001084 @Override
Igor Murashkina86ab6402013-08-30 12:58:36 -07001085 void updateSurface(Surface surface) throws OutOfResourcesException {
Romain Guy2a83f002011-01-18 18:28:21 -08001086 if (isRequested() && isEnabled()) {
Romain Guy786fc932012-07-24 16:24:56 -07001087 createEglSurface(surface);
Romain Guy2a83f002011-01-18 18:28:21 -08001088 }
1089 }
Romain Guy2d614592010-06-09 18:21:37 -07001090
Romain Guy5d6999e2012-03-22 19:15:04 -07001091 abstract HardwareCanvas createCanvas();
Romain Guye3924992010-06-10 18:51:21 -07001092
Romain Guy29d23ec2011-07-25 14:42:24 -07001093 abstract int[] getConfig(boolean dirtyRegions);
1094
Romain Guy3b748a42013-04-17 18:54:38 -07001095 boolean initializeEgl() {
Romain Guy566b3ef2011-07-18 18:38:12 -07001096 synchronized (sEglLock) {
1097 if (sEgl == null && sEglConfig == null) {
1098 sEgl = (EGL10) EGLContext.getEGL();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001099
Romain Guy566b3ef2011-07-18 18:38:12 -07001100 // Get to the default display.
Romain Guy484c7192011-07-25 11:56:33 -07001101 sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001102
Romain Guy484c7192011-07-25 11:56:33 -07001103 if (sEglDisplay == EGL_NO_DISPLAY) {
Romain Guy566b3ef2011-07-18 18:38:12 -07001104 throw new RuntimeException("eglGetDisplay failed "
Romain Guy407ec782011-08-24 17:06:58 -07001105 + GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guy566b3ef2011-07-18 18:38:12 -07001106 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001107
Romain Guy566b3ef2011-07-18 18:38:12 -07001108 // We can now initialize EGL for that display
1109 int[] version = new int[2];
1110 if (!sEgl.eglInitialize(sEglDisplay, version)) {
1111 throw new RuntimeException("eglInitialize failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001112 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guy566b3ef2011-07-18 18:38:12 -07001113 }
Romain Guy740ee652012-09-17 18:11:40 -07001114
1115 checkEglErrorsForced();
1116
Romain Guy5bb3c732012-11-29 17:52:58 -08001117 sEglConfig = loadEglConfig();
Romain Guy069ea0e2011-02-08 12:24:52 -08001118 }
1119 }
Romain Guy566b3ef2011-07-18 18:38:12 -07001120
Romain Guy5d6999e2012-03-22 19:15:04 -07001121 ManagedEGLContext managedContext = sEglContextStorage.get();
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001122 mEglContext = managedContext != null ? managedContext.getContext() : null;
Romain Guy566b3ef2011-07-18 18:38:12 -07001123 mEglThread = Thread.currentThread();
1124
1125 if (mEglContext == null) {
1126 mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
Romain Guy5d6999e2012-03-22 19:15:04 -07001127 sEglContextStorage.set(createManagedContext(mEglContext));
Romain Guy3b748a42013-04-17 18:54:38 -07001128 return true;
Romain Guy566b3ef2011-07-18 18:38:12 -07001129 }
Romain Guy3b748a42013-04-17 18:54:38 -07001130
1131 return false;
Romain Guy2d614592010-06-09 18:21:37 -07001132 }
1133
Romain Guy5bb3c732012-11-29 17:52:58 -08001134 private EGLConfig loadEglConfig() {
1135 EGLConfig eglConfig = chooseEglConfig();
1136 if (eglConfig == null) {
1137 // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
1138 if (sDirtyRegions) {
1139 sDirtyRegions = false;
1140 eglConfig = chooseEglConfig();
1141 if (eglConfig == null) {
1142 throw new RuntimeException("eglConfig not initialized");
1143 }
1144 } else {
1145 throw new RuntimeException("eglConfig not initialized");
1146 }
1147 }
1148 return eglConfig;
1149 }
1150
Romain Guy5d6999e2012-03-22 19:15:04 -07001151 abstract ManagedEGLContext createManagedContext(EGLContext eglContext);
1152
Romain Guye91a9c72011-05-02 14:53:30 -07001153 private EGLConfig chooseEglConfig() {
Romain Guye91a9c72011-05-02 14:53:30 -07001154 EGLConfig[] configs = new EGLConfig[1];
Romain Guy484c7192011-07-25 11:56:33 -07001155 int[] configsCount = new int[1];
Romain Guy7e1160e2011-07-08 15:49:50 -07001156 int[] configSpec = getConfig(sDirtyRegions);
Romain Guy484c7192011-07-25 11:56:33 -07001157
1158 // Debug
Romain Guy29d23ec2011-07-25 14:42:24 -07001159 final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
Romain Guy484c7192011-07-25 11:56:33 -07001160 if ("all".equalsIgnoreCase(debug)) {
1161 sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
1162
1163 EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
1164 sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
1165 configsCount[0], configsCount);
1166
1167 for (EGLConfig config : debugConfigs) {
1168 printConfig(config);
1169 }
1170 }
1171
Romain Guye91a9c72011-05-02 14:53:30 -07001172 if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
1173 throw new IllegalArgumentException("eglChooseConfig failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001174 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guye91a9c72011-05-02 14:53:30 -07001175 } else if (configsCount[0] > 0) {
Romain Guy484c7192011-07-25 11:56:33 -07001176 if ("choice".equalsIgnoreCase(debug)) {
1177 printConfig(configs[0]);
1178 }
Romain Guye91a9c72011-05-02 14:53:30 -07001179 return configs[0];
1180 }
Romain Guy484c7192011-07-25 11:56:33 -07001181
Romain Guye91a9c72011-05-02 14:53:30 -07001182 return null;
1183 }
1184
Romain Guye979e622012-03-20 13:50:27 -07001185 private static void printConfig(EGLConfig config) {
Romain Guy484c7192011-07-25 11:56:33 -07001186 int[] value = new int[1];
1187
1188 Log.d(LOG_TAG, "EGL configuration " + config + ":");
1189
1190 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
1191 Log.d(LOG_TAG, " RED_SIZE = " + value[0]);
1192
1193 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
1194 Log.d(LOG_TAG, " GREEN_SIZE = " + value[0]);
1195
1196 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
1197 Log.d(LOG_TAG, " BLUE_SIZE = " + value[0]);
1198
1199 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
1200 Log.d(LOG_TAG, " ALPHA_SIZE = " + value[0]);
1201
1202 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
1203 Log.d(LOG_TAG, " DEPTH_SIZE = " + value[0]);
1204
1205 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
1206 Log.d(LOG_TAG, " STENCIL_SIZE = " + value[0]);
1207
Romain Guy8efca542012-10-15 18:09:49 -07001208 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value);
1209 Log.d(LOG_TAG, " SAMPLE_BUFFERS = " + value[0]);
1210
1211 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value);
1212 Log.d(LOG_TAG, " SAMPLES = " + value[0]);
1213
Romain Guy484c7192011-07-25 11:56:33 -07001214 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
Romain Guy29d23ec2011-07-25 14:42:24 -07001215 Log.d(LOG_TAG, " SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
Romain Guy8efca542012-10-15 18:09:49 -07001216
1217 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value);
1218 Log.d(LOG_TAG, " CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
Romain Guy484c7192011-07-25 11:56:33 -07001219 }
1220
Igor Murashkina86ab6402013-08-30 12:58:36 -07001221 GL createEglSurface(Surface surface) throws OutOfResourcesException {
Romain Guye3924992010-06-10 18:51:21 -07001222 // Check preconditions.
Romain Guyfb8b7632010-08-23 21:05:08 -07001223 if (sEgl == null) {
Romain Guye3924992010-06-10 18:51:21 -07001224 throw new RuntimeException("egl not initialized");
Romain Guy2d614592010-06-09 18:21:37 -07001225 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001226 if (sEglDisplay == null) {
Romain Guye3924992010-06-10 18:51:21 -07001227 throw new RuntimeException("eglDisplay not initialized");
1228 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001229 if (sEglConfig == null) {
Romain Guy069ea0e2011-02-08 12:24:52 -08001230 throw new RuntimeException("eglConfig not initialized");
Romain Guye3924992010-06-10 18:51:21 -07001231 }
Romain Guy566b3ef2011-07-18 18:38:12 -07001232 if (Thread.currentThread() != mEglThread) {
Igor Murashkina86ab6402013-08-30 12:58:36 -07001233 throw new IllegalStateException("HardwareRenderer cannot be used "
Romain Guyfb8b7632010-08-23 21:05:08 -07001234 + "from multiple threads");
1235 }
Romain Guye3924992010-06-10 18:51:21 -07001236
Romain Guy6d7475d2011-07-27 16:28:21 -07001237 // In case we need to destroy an existing surface
1238 destroySurface();
Romain Guye3924992010-06-10 18:51:21 -07001239
1240 // Create an EGL surface we can render into.
Romain Guy786fc932012-07-24 16:24:56 -07001241 if (!createSurface(surface)) {
Romain Guy1d0c7082011-08-03 16:22:24 -07001242 return null;
Romain Guye3924992010-06-10 18:51:21 -07001243 }
1244
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001245 initCaches();
Romain Guy6f7d9392011-06-02 14:17:28 -07001246
Romain Guy9477c6e2011-12-09 12:27:21 -08001247 return mEglContext.getGL();
1248 }
1249
1250 private void enableDirtyRegions() {
Romain Guy6f7d9392011-06-02 14:17:28 -07001251 // If mDirtyRegions is set, this means we have an EGL configuration
1252 // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
Romain Guy7e1160e2011-07-08 15:49:50 -07001253 if (sDirtyRegions) {
Romain Guy244ada12012-03-28 16:41:26 -07001254 if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001255 Log.w(LOG_TAG, "Backbuffer cannot be preserved");
1256 }
Romain Guy7e1160e2011-07-08 15:49:50 -07001257 } else if (sDirtyRegionsRequested) {
Romain Guy6f7d9392011-06-02 14:17:28 -07001258 // If mDirtyRegions is not set, our EGL configuration does not
1259 // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
1260 // swap behavior might be EGL_BUFFER_PRESERVED, which means we
1261 // want to set mDirtyRegions. We try to do this only if dirty
1262 // regions were initially requested as part of the device
1263 // configuration (see RENDER_DIRTY_REGIONS)
Romain Guy244ada12012-03-28 16:41:26 -07001264 mDirtyRegionsEnabled = isBackBufferPreserved();
Romain Guy7d7b5492011-01-24 16:33:45 -08001265 }
Romain Guye3924992010-06-10 18:51:21 -07001266 }
1267
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001268 abstract void initCaches();
Romain Guy3b748a42013-04-17 18:54:38 -07001269 abstract void initAtlas();
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001270
Romain Guye3924992010-06-10 18:51:21 -07001271 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
Romain Guybd431522012-09-26 13:31:25 -07001272 int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
Romain Guye3924992010-06-10 18:51:21 -07001273
Romain Guyc0029362012-09-24 20:18:13 -07001274 EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
1275 mGlVersion != 0 ? attribs : null);
Romain Guyed1b6f42012-09-24 21:42:18 -07001276 if (context == null || context == EGL_NO_CONTEXT) {
Romain Guyc0029362012-09-24 20:18:13 -07001277 //noinspection ConstantConditions
1278 throw new IllegalStateException(
1279 "Could not create an EGL context. eglCreateContext failed with error: " +
1280 GLUtils.getEGLErrorString(sEgl.eglGetError()));
1281 }
Romain Guy3b748a42013-04-17 18:54:38 -07001282
Romain Guyc0029362012-09-24 20:18:13 -07001283 return context;
Romain Guy2d614592010-06-09 18:21:37 -07001284 }
1285
1286 @Override
Romain Guy4caa4ed2010-08-25 14:46:24 -07001287 void destroy(boolean full) {
1288 if (full && mCanvas != null) {
Romain Guy4caa4ed2010-08-25 14:46:24 -07001289 mCanvas = null;
1290 }
Romain Guye3924992010-06-10 18:51:21 -07001291
Romain Guy357c9422011-08-02 11:32:49 -07001292 if (!isEnabled() || mDestroyed) {
1293 setEnabled(false);
1294 return;
1295 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001296
Romain Guy6d7475d2011-07-27 16:28:21 -07001297 destroySurface();
Romain Guye3924992010-06-10 18:51:21 -07001298 setEnabled(false);
Romain Guy357c9422011-08-02 11:32:49 -07001299
1300 mDestroyed = true;
1301 mGl = null;
Romain Guyfb8b7632010-08-23 21:05:08 -07001302 }
1303
Romain Guy6d7475d2011-07-27 16:28:21 -07001304 void destroySurface() {
1305 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
Romain Guyc8ba0b42013-06-21 16:40:30 -07001306 if (mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
1307 sEgl.eglMakeCurrent(sEglDisplay,
1308 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1309 }
Romain Guy6d7475d2011-07-27 16:28:21 -07001310 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
1311 mEglSurface = null;
1312 }
1313 }
1314
Romain Guye3924992010-06-10 18:51:21 -07001315 @Override
Romain Guy786fc932012-07-24 16:24:56 -07001316 void invalidate(Surface surface) {
Romain Guy7e1160e2011-07-08 15:49:50 -07001317 // Cancels any existing buffer to ensure we'll get a buffer
1318 // of the right size before we call eglSwapBuffers
Romain Guycf15efb2011-08-02 12:59:32 -07001319 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
Romain Guy1d0c7082011-08-03 16:22:24 -07001320
Romain Guyd3facf32011-08-03 11:14:38 -07001321 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
1322 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
Romain Guy1d0c7082011-08-03 16:22:24 -07001323 mEglSurface = null;
1324 setEnabled(false);
Romain Guyd3facf32011-08-03 11:14:38 -07001325 }
Romain Guycf15efb2011-08-02 12:59:32 -07001326
Romain Guy786fc932012-07-24 16:24:56 -07001327 if (surface.isValid()) {
1328 if (!createSurface(surface)) {
Romain Guy1d0c7082011-08-03 16:22:24 -07001329 return;
Romain Guycf15efb2011-08-02 12:59:32 -07001330 }
Romain Guy9477c6e2011-12-09 12:27:21 -08001331
1332 mUpdateDirtyRegions = true;
1333
Romain Guy86e3e222011-08-16 14:30:08 -07001334 if (mCanvas != null) {
1335 setEnabled(true);
1336 }
Romain Guycf15efb2011-08-02 12:59:32 -07001337 }
Romain Guy03985752011-07-11 15:33:51 -07001338 }
Romain Guycf15efb2011-08-02 12:59:32 -07001339
Romain Guy786fc932012-07-24 16:24:56 -07001340 private boolean createSurface(Surface surface) {
1341 mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
Romain Guy1d0c7082011-08-03 16:22:24 -07001342
1343 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
1344 int error = sEgl.eglGetError();
1345 if (error == EGL_BAD_NATIVE_WINDOW) {
1346 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
1347 return false;
1348 }
1349 throw new RuntimeException("createWindowSurface failed "
Romain Guy407ec782011-08-24 17:06:58 -07001350 + GLUtils.getEGLErrorString(error));
Romain Guy1d0c7082011-08-03 16:22:24 -07001351 }
Romain Guybd431522012-09-26 13:31:25 -07001352
1353 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
1354 throw new IllegalStateException("eglMakeCurrent failed " +
1355 GLUtils.getEGLErrorString(sEgl.eglGetError()));
1356 }
1357
1358 enableDirtyRegions();
1359
Romain Guy1d0c7082011-08-03 16:22:24 -07001360 return true;
1361 }
1362
Romain Guy03985752011-07-11 15:33:51 -07001363 @Override
1364 boolean validate() {
Romain Guycc6b7caf2013-06-24 19:19:21 -07001365 return checkRenderContext() != SURFACE_STATE_ERROR;
Romain Guy7e1160e2011-07-08 15:49:50 -07001366 }
1367
1368 @Override
Romain Guyfb8b7632010-08-23 21:05:08 -07001369 void setup(int width, int height) {
Romain Guyeca9b1f2011-08-26 13:36:37 -07001370 if (validate()) {
1371 mCanvas.setViewport(width, height);
Chet Haase40e03832011-10-06 08:34:13 -07001372 mWidth = width;
1373 mHeight = height;
Romain Guyeca9b1f2011-08-26 13:36:37 -07001374 }
Romain Guye3924992010-06-10 18:51:21 -07001375 }
Romain Guy7d7b5492011-01-24 16:33:45 -08001376
Chet Haase40e03832011-10-06 08:34:13 -07001377 @Override
1378 int getWidth() {
1379 return mWidth;
1380 }
1381
1382 @Override
1383 int getHeight() {
1384 return mHeight;
1385 }
1386
Chet Haase08837c22011-11-28 11:53:21 -08001387 @Override
1388 HardwareCanvas getCanvas() {
1389 return mCanvas;
1390 }
1391
Romain Guyef359272013-01-31 19:07:29 -08001392 @Override
1393 void setName(String name) {
1394 mName = name;
1395 }
1396
Romain Guye3924992010-06-10 18:51:21 -07001397 boolean canDraw() {
1398 return mGl != null && mCanvas != null;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001399 }
1400
Chet Haase44b2fe32012-06-06 19:03:58 -07001401 int onPreDraw(Rect dirty) {
1402 return DisplayList.STATUS_DONE;
Romain Guye3924992010-06-10 18:51:21 -07001403 }
1404
Romain Guyb025b9c2010-09-16 14:16:48 -07001405 void onPostDraw() {
1406 }
Romain Guye3924992010-06-10 18:51:21 -07001407
Romain Guy8f3b8e32012-03-27 16:33:45 -07001408 class FunctorsRunnable implements Runnable {
1409 View.AttachInfo attachInfo;
1410
1411 @Override
1412 public void run() {
1413 final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
1414 if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
1415 return;
1416 }
1417
Romain Guycc6b7caf2013-06-24 19:19:21 -07001418 if (checkRenderContext() != SURFACE_STATE_ERROR) {
Romain Guy8f3b8e32012-03-27 16:33:45 -07001419 int status = mCanvas.invokeFunctors(mRedrawClip);
1420 handleFunctorStatus(attachInfo, status);
1421 }
1422 }
1423 }
1424
Romain Guye3924992010-06-10 18:51:21 -07001425 @Override
Romain Guye55945e2013-04-04 15:26:04 -07001426 void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Romain Guy7d7b5492011-01-24 16:33:45 -08001427 Rect dirty) {
Romain Guye3924992010-06-10 18:51:21 -07001428 if (canDraw()) {
Romain Guy02ccac62011-06-24 13:20:23 -07001429 if (!hasDirtyRegions()) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001430 dirty = null;
1431 }
Romain Guye3924992010-06-10 18:51:21 -07001432 attachInfo.mIgnoreDirtyState = true;
Romain Guy02ccac62011-06-24 13:20:23 -07001433 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
1434
Dianne Hackborn4702a852012-08-17 15:18:29 -07001435 view.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy03985752011-07-11 15:33:51 -07001436
Romain Guycc6b7caf2013-06-24 19:19:21 -07001437 // We are already on the correct thread
1438 final int surfaceState = checkRenderContextUnsafe();
Romain Guyd88f54c2011-01-24 20:22:49 -08001439 if (surfaceState != SURFACE_STATE_ERROR) {
Romain Guy76878822012-03-30 14:54:22 -07001440 HardwareCanvas canvas = mCanvas;
1441 attachInfo.mHardwareCanvas = canvas;
Romain Guy77e67cf2012-06-19 16:38:50 -07001442
1443 if (mProfileEnabled) {
1444 mProfileLock.lock();
1445 }
1446
Romain Guy672433d2013-01-04 19:05:13 -08001447 dirty = beginFrame(canvas, dirty, surfaceState);
Romain Guyd88f54c2011-01-24 20:22:49 -08001448
Romain Guyd17043d2013-02-19 14:12:55 -08001449 DisplayList displayList = buildDisplayList(view, canvas);
1450
Romain Guycc6b7caf2013-06-24 19:19:21 -07001451 // buildDisplayList() calls into user code which can cause
1452 // an eglMakeCurrent to happen with a different surface/context.
1453 // We must therefore check again here.
1454 if (checkRenderContextUnsafe() == SURFACE_STATE_ERROR) {
1455 return;
1456 }
1457
Romain Guy2b7028e2012-09-19 17:25:38 -07001458 int saveCount = 0;
1459 int status = DisplayList.STATUS_DONE;
Chet Haasedaf98e92011-01-10 14:10:36 -08001460
Romain Guye9bc11f2013-05-23 12:47:26 -07001461 long start = getSystemTime();
Romain Guyb8c0de22010-12-13 14:42:34 -08001462 try {
Romain Guy672433d2013-01-04 19:05:13 -08001463 status = prepareFrame(dirty);
Jeff Brown95db2b22011-11-30 19:54:41 -08001464
Romain Guy2b7028e2012-09-19 17:25:38 -07001465 saveCount = canvas.save();
1466 callbacks.onHardwarePreDraw(canvas);
1467
Chet Haasedaf98e92011-01-10 14:10:36 -08001468 if (displayList != null) {
Chet Haase58d110a2013-04-10 07:43:29 -07001469 status |= drawDisplayList(attachInfo, canvas, displayList, status);
Chet Haasedaf98e92011-01-10 14:10:36 -08001470 } else {
1471 // Shouldn't reach here
1472 view.draw(canvas);
1473 }
Romain Guyd17043d2013-02-19 14:12:55 -08001474 } catch (Exception e) {
1475 Log.e(LOG_TAG, "An error has occurred while drawing:", e);
Romain Guyb04f7e92012-02-15 12:36:54 -08001476 } finally {
1477 callbacks.onHardwarePostDraw(canvas);
1478 canvas.restoreToCount(saveCount);
1479 view.mRecreateDisplayList = false;
Romain Guy19f86e82012-04-23 15:19:07 -07001480
Romain Guye9bc11f2013-05-23 12:47:26 -07001481 mDrawDelta = getSystemTime() - start;
Romain Guy78dd96d2013-05-03 14:24:16 -07001482
Romain Guye9bc11f2013-05-23 12:47:26 -07001483 if (mDrawDelta > 0) {
1484 mFrameCount++;
Romain Guy19f86e82012-04-23 15:19:07 -07001485
Romain Guye9bc11f2013-05-23 12:47:26 -07001486 debugOverdraw(attachInfo, dirty, canvas, displayList);
1487 debugDirtyRegions(dirty, canvas);
1488 drawProfileData(attachInfo);
1489 }
Romain Guyb8c0de22010-12-13 14:42:34 -08001490 }
Chet Haasedaf98e92011-01-10 14:10:36 -08001491
Romain Guyb8c0de22010-12-13 14:42:34 -08001492 onPostDraw();
Chet Haasedaf98e92011-01-10 14:10:36 -08001493
Romain Guy672433d2013-01-04 19:05:13 -08001494 swapBuffers(status);
Jeff Brown95db2b22011-11-30 19:54:41 -08001495
Romain Guy77e67cf2012-06-19 16:38:50 -07001496 if (mProfileEnabled) {
1497 mProfileLock.unlock();
1498 }
1499
Romain Guy672433d2013-01-04 19:05:13 -08001500 attachInfo.mIgnoreDirtyState = false;
Romain Guye3924992010-06-10 18:51:21 -07001501 }
Romain Guye3924992010-06-10 18:51:21 -07001502 }
1503 }
Romain Guy03985752011-07-11 15:33:51 -07001504
Romain Guy78dd96d2013-05-03 14:24:16 -07001505 abstract void countOverdraw(HardwareCanvas canvas);
1506 abstract float getOverdraw(HardwareCanvas canvas);
1507
1508 private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
1509 HardwareCanvas canvas, DisplayList displayList) {
1510
1511 if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
Romain Guy78dd96d2013-05-03 14:24:16 -07001512 if (mDebugOverdrawLayer == null) {
1513 mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
1514 } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
1515 mDebugOverdrawLayer.getHeight() != mHeight) {
1516 mDebugOverdrawLayer.resize(mWidth, mHeight);
1517 }
1518
1519 if (!mDebugOverdrawLayer.isValid()) {
1520 mDebugOverdraw = -1;
1521 return;
1522 }
1523
1524 HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
1525 countOverdraw(layerCanvas);
1526 final int restoreCount = layerCanvas.save();
1527 layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
1528 layerCanvas.restoreToCount(restoreCount);
1529 mDebugOverdrawLayer.end(canvas);
1530
1531 float overdraw = getOverdraw(layerCanvas);
1532 DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
1533
1534 drawOverdrawCounter(canvas, overdraw, metrics.density);
1535 }
1536 }
1537
1538 private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
1539 final String text = String.format("%.2fx", overdraw);
1540 final Paint paint = setupPaint(density);
1541 // HSBtoColor will clamp the values in the 0..1 range
1542 paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
1543
1544 canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
1545 }
1546
1547 private Paint setupPaint(float density) {
1548 if (mDebugOverdrawPaint == null) {
1549 mDebugOverdrawPaint = new Paint();
1550 mDebugOverdrawPaint.setAntiAlias(true);
1551 mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
1552 mDebugOverdrawPaint.setTextSize(density * 20.0f);
1553 }
1554 return mDebugOverdrawPaint;
1555 }
1556
Romain Guyd17043d2013-02-19 14:12:55 -08001557 private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
Romain Guye9bc11f2013-05-23 12:47:26 -07001558 if (mDrawDelta <= 0) {
1559 return view.mDisplayList;
1560 }
1561
Romain Guyd17043d2013-02-19 14:12:55 -08001562 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
1563 == View.PFLAG_INVALIDATED;
1564 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
1565
1566 long buildDisplayListStartTime = startBuildDisplayListProfiling();
1567 canvas.clearLayerUpdates();
1568
1569 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
1570 DisplayList displayList = view.getDisplayList();
1571 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1572
1573 endBuildDisplayListProfiling(buildDisplayListStartTime);
1574
1575 return displayList;
1576 }
1577
Romain Guy98e4a522013-01-07 10:58:34 -08001578 abstract void drawProfileData(View.AttachInfo attachInfo);
Romain Guy672433d2013-01-04 19:05:13 -08001579
1580 private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
1581 // We had to change the current surface and/or context, redraw everything
1582 if (surfaceState == SURFACE_STATE_UPDATED) {
1583 dirty = null;
1584 beginFrame(null);
1585 } else {
1586 int[] size = mSurfaceSize;
1587 beginFrame(size);
1588
1589 if (size[1] != mHeight || size[0] != mWidth) {
1590 mWidth = size[0];
1591 mHeight = size[1];
1592
1593 canvas.setViewport(mWidth, mHeight);
1594
1595 dirty = null;
1596 }
1597 }
1598
Romain Guy48ef4a92013-01-10 18:38:46 -08001599 if (mDebugDataProvider != null) dirty = null;
Romain Guy672433d2013-01-04 19:05:13 -08001600
1601 return dirty;
1602 }
1603
1604 private long startBuildDisplayListProfiling() {
1605 if (mProfileEnabled) {
1606 mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
1607 if (mProfileCurrentFrame >= mProfileData.length) {
1608 mProfileCurrentFrame = 0;
1609 }
1610
1611 return System.nanoTime();
1612 }
1613 return 0;
1614 }
1615
1616 private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
1617 if (mProfileEnabled) {
1618 long now = System.nanoTime();
1619 float total = (now - getDisplayListStartTime) * 0.000001f;
1620 //noinspection PointlessArithmeticExpression
1621 mProfileData[mProfileCurrentFrame] = total;
1622 }
1623 }
1624
Romain Guy672433d2013-01-04 19:05:13 -08001625 private int prepareFrame(Rect dirty) {
1626 int status;
1627 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
1628 try {
1629 status = onPreDraw(dirty);
1630 } finally {
1631 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1632 }
1633 return status;
1634 }
1635
1636 private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
1637 DisplayList displayList, int status) {
1638
1639 long drawDisplayListStartTime = 0;
1640 if (mProfileEnabled) {
1641 drawDisplayListStartTime = System.nanoTime();
1642 }
1643
1644 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
1645 try {
1646 status |= canvas.drawDisplayList(displayList, mRedrawClip,
1647 DisplayList.FLAG_CLIP_CHILDREN);
1648 } finally {
1649 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1650 }
1651
1652 if (mProfileEnabled) {
1653 long now = System.nanoTime();
1654 float total = (now - drawDisplayListStartTime) * 0.000001f;
1655 mProfileData[mProfileCurrentFrame + 1] = total;
1656 }
1657
1658 handleFunctorStatus(attachInfo, status);
1659 return status;
1660 }
1661
1662 private void swapBuffers(int status) {
1663 if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
1664 long eglSwapBuffersStartTime = 0;
1665 if (mProfileEnabled) {
1666 eglSwapBuffersStartTime = System.nanoTime();
1667 }
1668
1669 sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
1670
1671 if (mProfileEnabled) {
1672 long now = System.nanoTime();
1673 float total = (now - eglSwapBuffersStartTime) * 0.000001f;
1674 mProfileData[mProfileCurrentFrame + 2] = total;
1675 }
1676
1677 checkEglErrors();
1678 }
1679 }
1680
1681 private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
1682 if (mDebugDirtyRegions) {
1683 if (mDebugPaint == null) {
1684 mDebugPaint = new Paint();
1685 mDebugPaint.setColor(0x7fff0000);
1686 }
1687
1688 if (dirty != null && (mFrameCount & 1) == 0) {
1689 canvas.drawRect(dirty, mDebugPaint);
1690 }
1691 }
1692 }
1693
Romain Guy8f3b8e32012-03-27 16:33:45 -07001694 private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
1695 // If the draw flag is set, functors will be invoked while executing
1696 // the tree of display lists
1697 if ((status & DisplayList.STATUS_DRAW) != 0) {
1698 if (mRedrawClip.isEmpty()) {
1699 attachInfo.mViewRootImpl.invalidate();
1700 } else {
1701 attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
1702 mRedrawClip.setEmpty();
1703 }
1704 }
1705
Chris Craik9efa2222012-12-04 15:15:31 -08001706 if ((status & DisplayList.STATUS_INVOKE) != 0 ||
1707 attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
1708 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
1709 mFunctorsRunnable.attachInfo = attachInfo;
1710 attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
Romain Guy8f3b8e32012-03-27 16:33:45 -07001711 }
1712 }
1713
Romain Guyba6be8a2012-04-23 18:22:09 -07001714 @Override
Ashok Bhata0398432014-01-20 20:08:01 +00001715 void detachFunctor(long functor) {
Romain Guyba6be8a2012-04-23 18:22:09 -07001716 if (mCanvas != null) {
1717 mCanvas.detachFunctor(functor);
Chris Craik932b7f62012-06-06 13:59:33 -07001718 }
Romain Guyba6be8a2012-04-23 18:22:09 -07001719 }
1720
1721 @Override
Ashok Bhata0398432014-01-20 20:08:01 +00001722 boolean attachFunctor(View.AttachInfo attachInfo, long functor) {
Romain Guyba6be8a2012-04-23 18:22:09 -07001723 if (mCanvas != null) {
1724 mCanvas.attachFunctor(functor);
Chris Craik9efa2222012-12-04 15:15:31 -08001725 mFunctorsRunnable.attachInfo = attachInfo;
1726 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
1727 attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0);
Chris Craik41ee4652012-05-31 15:05:57 -07001728 return true;
Romain Guyba6be8a2012-04-23 18:22:09 -07001729 }
Chris Craik41ee4652012-05-31 15:05:57 -07001730 return false;
Romain Guyba6be8a2012-04-23 18:22:09 -07001731 }
1732
Romain Guy03985752011-07-11 15:33:51 -07001733 /**
Romain Guycc6b7caf2013-06-24 19:19:21 -07001734 * Ensures the current EGL context and surface are the ones we expect.
1735 * This method throws an IllegalStateException if invoked from a thread
1736 * that did not initialize EGL.
Igor Murashkina86ab6402013-08-30 12:58:36 -07001737 *
Romain Guy03985752011-07-11 15:33:51 -07001738 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
1739 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
1740 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
Romain Guycc6b7caf2013-06-24 19:19:21 -07001741 *
1742 * @see #checkRenderContextUnsafe()
Romain Guy03985752011-07-11 15:33:51 -07001743 */
Romain Guycc6b7caf2013-06-24 19:19:21 -07001744 int checkRenderContext() {
Romain Guy566b3ef2011-07-18 18:38:12 -07001745 if (mEglThread != Thread.currentThread()) {
Romain Guy03985752011-07-11 15:33:51 -07001746 throw new IllegalStateException("Hardware acceleration can only be used with a " +
Romain Guy566b3ef2011-07-18 18:38:12 -07001747 "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
Romain Guy03985752011-07-11 15:33:51 -07001748 "Current thread: " + Thread.currentThread());
1749 }
1750
Romain Guycc6b7caf2013-06-24 19:19:21 -07001751 return checkRenderContextUnsafe();
1752 }
1753
1754 /**
1755 * Ensures the current EGL context and surface are the ones we expect.
1756 * This method does not check the current thread.
1757 *
1758 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
1759 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
1760 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
1761 *
1762 * @see #checkRenderContext()
1763 */
1764 private int checkRenderContextUnsafe() {
1765 if (!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) ||
1766 !mEglContext.equals(sEgl.eglGetCurrentContext())) {
Romain Guy566b3ef2011-07-18 18:38:12 -07001767 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
Romain Guy9745fae2010-12-08 11:39:15 -08001768 Log.e(LOG_TAG, "eglMakeCurrent failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001769 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guyeca9b1f2011-08-26 13:36:37 -07001770 fallback(true);
Romain Guyd88f54c2011-01-24 20:22:49 -08001771 return SURFACE_STATE_ERROR;
1772 } else {
Romain Guy9477c6e2011-12-09 12:27:21 -08001773 if (mUpdateDirtyRegions) {
1774 enableDirtyRegions();
1775 mUpdateDirtyRegions = false;
1776 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001777 return SURFACE_STATE_UPDATED;
Romain Guyfb8b7632010-08-23 21:05:08 -07001778 }
1779 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001780 return SURFACE_STATE_SUCCESS;
Romain Guyfb8b7632010-08-23 21:05:08 -07001781 }
Romain Guy48ef4a92013-01-10 18:38:46 -08001782
1783 private static int dpToPx(int dp, float density) {
1784 return (int) (dp * density + 0.5f);
1785 }
1786
1787 class DrawPerformanceDataProvider extends GraphDataProvider {
1788 private final int mGraphType;
1789
1790 private int mVerticalUnit;
1791 private int mHorizontalUnit;
1792 private int mHorizontalMargin;
1793 private int mThresholdStroke;
1794
1795 DrawPerformanceDataProvider(int graphType) {
1796 mGraphType = graphType;
1797 }
1798
1799 @Override
1800 void prepare(DisplayMetrics metrics) {
1801 final float density = metrics.density;
1802
1803 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
1804 mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
1805 mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
1806 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
1807 }
1808
1809 @Override
1810 int getGraphType() {
1811 return mGraphType;
1812 }
1813
1814 @Override
1815 int getVerticalUnitSize() {
1816 return mVerticalUnit;
1817 }
1818
1819 @Override
1820 int getHorizontalUnitSize() {
1821 return mHorizontalUnit;
1822 }
1823
1824 @Override
1825 int getHorizontaUnitMargin() {
1826 return mHorizontalMargin;
1827 }
1828
1829 @Override
1830 float[] getData() {
1831 return mProfileData;
1832 }
1833
1834 @Override
1835 float getThreshold() {
1836 return 16;
1837 }
1838
1839 @Override
1840 int getFrameCount() {
1841 return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
1842 }
1843
1844 @Override
1845 int getElementCount() {
1846 return PROFILE_FRAME_DATA_COUNT;
1847 }
1848
1849 @Override
1850 int getCurrentFrame() {
1851 return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
1852 }
1853
1854 @Override
1855 void setupGraphPaint(Paint paint, int elementIndex) {
1856 paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
1857 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
1858 }
1859
1860 @Override
1861 void setupThresholdPaint(Paint paint) {
1862 paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
1863 paint.setStrokeWidth(mThresholdStroke);
1864 }
1865
1866 @Override
1867 void setupCurrentFramePaint(Paint paint) {
1868 paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
1869 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
1870 }
1871 }
Romain Guye3924992010-06-10 18:51:21 -07001872 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001873
Romain Guye3924992010-06-10 18:51:21 -07001874 /**
1875 * Hardware renderer using OpenGL ES 2.0.
1876 */
1877 static class Gl20Renderer extends GlRenderer {
Romain Guye4d01122010-06-16 18:44:05 -07001878 private GLES20Canvas mGlCanvas;
1879
Romain Guy98e4a522013-01-07 10:58:34 -08001880 private DisplayMetrics mDisplayMetrics;
1881
Romain Guy912a7b32011-07-26 18:57:28 -07001882 private static EGLSurface sPbuffer;
1883 private static final Object[] sPbufferLock = new Object[0];
1884
Romain Guy31f2c2e2011-11-21 10:55:41 -08001885 static class Gl20RendererEglContext extends ManagedEGLContext {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001886 final Handler mHandler = new Handler();
1887
Romain Guy31f2c2e2011-11-21 10:55:41 -08001888 public Gl20RendererEglContext(EGLContext context) {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001889 super(context);
1890 }
1891
1892 @Override
1893 public void onTerminate(final EGLContext eglContext) {
1894 // Make sure we do this on the correct thread.
1895 if (mHandler.getLooper() != Looper.myLooper()) {
1896 mHandler.post(new Runnable() {
Romain Guy5d6999e2012-03-22 19:15:04 -07001897 @Override
1898 public void run() {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001899 onTerminate(eglContext);
1900 }
1901 });
1902 return;
1903 }
1904
1905 synchronized (sEglLock) {
1906 if (sEgl == null) return;
1907
1908 if (EGLImpl.getInitCount(sEglDisplay) == 1) {
1909 usePbufferSurface(eglContext);
1910 GLES20Canvas.terminateCaches();
1911
1912 sEgl.eglDestroyContext(sEglDisplay, eglContext);
Romain Guya998dff2012-03-23 18:58:36 -07001913 sEglContextStorage.set(null);
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001914 sEglContextStorage.remove();
1915
1916 sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
Romain Guy31f2c2e2011-11-21 10:55:41 -08001917 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
1918 EGL_NO_SURFACE, EGL_NO_CONTEXT);
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001919
1920 sEgl.eglReleaseThread();
1921 sEgl.eglTerminate(sEglDisplay);
1922
1923 sEgl = null;
1924 sEglDisplay = null;
1925 sEglConfig = null;
1926 sPbuffer = null;
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001927 }
1928 }
1929 }
1930 }
1931
Romain Guye4d01122010-06-16 18:44:05 -07001932 Gl20Renderer(boolean translucent) {
1933 super(2, translucent);
Romain Guye3924992010-06-10 18:51:21 -07001934 }
1935
1936 @Override
Romain Guy5d6999e2012-03-22 19:15:04 -07001937 HardwareCanvas createCanvas() {
Romain Guy6b7bd242010-10-06 19:49:23 -07001938 return mGlCanvas = new GLES20Canvas(mTranslucent);
Romain Guye4d01122010-06-16 18:44:05 -07001939 }
Romain Guye91a9c72011-05-02 14:53:30 -07001940
1941 @Override
Romain Guy5d6999e2012-03-22 19:15:04 -07001942 ManagedEGLContext createManagedContext(EGLContext eglContext) {
1943 return new Gl20Renderer.Gl20RendererEglContext(mEglContext);
1944 }
1945
1946 @Override
Romain Guye91a9c72011-05-02 14:53:30 -07001947 int[] getConfig(boolean dirtyRegions) {
Romain Guy8ce00302013-01-15 18:51:42 -08001948 //noinspection PointlessBooleanExpression,ConstantConditions
1949 final int stencilSize = GLES20Canvas.getStencilSize();
Romain Guy735738c2012-12-03 12:34:51 -08001950 final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
1951
Romain Guye91a9c72011-05-02 14:53:30 -07001952 return new int[] {
Romain Guybd431522012-09-26 13:31:25 -07001953 EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
Romain Guy484c7192011-07-25 11:56:33 -07001954 EGL_RED_SIZE, 8,
1955 EGL_GREEN_SIZE, 8,
1956 EGL_BLUE_SIZE, 8,
1957 EGL_ALPHA_SIZE, 8,
1958 EGL_DEPTH_SIZE, 0,
Romain Guy8efca542012-10-15 18:09:49 -07001959 EGL_CONFIG_CAVEAT, EGL_NONE,
Romain Guy735738c2012-12-03 12:34:51 -08001960 EGL_STENCIL_SIZE, stencilSize,
1961 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
Romain Guy484c7192011-07-25 11:56:33 -07001962 EGL_NONE
Romain Guye91a9c72011-05-02 14:53:30 -07001963 };
1964 }
Romain Guy735738c2012-12-03 12:34:51 -08001965
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001966 @Override
1967 void initCaches() {
Romain Guy3b748a42013-04-17 18:54:38 -07001968 if (GLES20Canvas.initCaches()) {
1969 // Caches were (re)initialized, rebind atlas
1970 initAtlas();
1971 }
1972 }
1973
1974 @Override
1975 void initAtlas() {
1976 IBinder binder = ServiceManager.getService("assetatlas");
Romain Guy927bc7d2013-05-03 11:32:09 -07001977 if (binder == null) return;
1978
Romain Guy3b748a42013-04-17 18:54:38 -07001979 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
1980 try {
Romain Guy80b12fc2013-05-29 15:54:25 -07001981 if (atlas.isCompatible(android.os.Process.myPpid())) {
1982 GraphicBuffer buffer = atlas.getBuffer();
1983 if (buffer != null) {
1984 int[] map = atlas.getMap();
1985 if (map != null) {
1986 GLES20Canvas.initAtlas(buffer, map);
1987 }
Romain Guycb883302013-08-07 15:03:40 -07001988 // If IAssetAtlas is not the same class as the IBinder
1989 // we are using a remote service and we can safely
1990 // destroy the graphic buffer
1991 if (atlas.getClass() != binder.getClass()) {
1992 buffer.destroy();
1993 }
Romain Guy3b748a42013-04-17 18:54:38 -07001994 }
1995 }
1996 } catch (RemoteException e) {
1997 Log.w(LOG_TAG, "Could not acquire atlas", e);
1998 }
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001999 }
Romain Guye91a9c72011-05-02 14:53:30 -07002000
Romain Guyb8c0de22010-12-13 14:42:34 -08002001 @Override
2002 boolean canDraw() {
2003 return super.canDraw() && mGlCanvas != null;
Romain Guycb883302013-08-07 15:03:40 -07002004 }
Romain Guye4d01122010-06-16 18:44:05 -07002005
2006 @Override
Chet Haase44b2fe32012-06-06 19:03:58 -07002007 int onPreDraw(Rect dirty) {
2008 return mGlCanvas.onPreDraw(dirty);
Romain Guye3924992010-06-10 18:51:21 -07002009 }
2010
Romain Guyb025b9c2010-09-16 14:16:48 -07002011 @Override
2012 void onPostDraw() {
2013 mGlCanvas.onPostDraw();
2014 }
2015
Romain Guyb051e892010-09-28 19:09:36 -07002016 @Override
Romain Guy98e4a522013-01-07 10:58:34 -08002017 void drawProfileData(View.AttachInfo attachInfo) {
Romain Guy48ef4a92013-01-10 18:38:46 -08002018 if (mDebugDataProvider != null) {
2019 final GraphDataProvider provider = mDebugDataProvider;
2020 initProfileDrawData(attachInfo, provider);
Romain Guy98e4a522013-01-07 10:58:34 -08002021
Romain Guy48ef4a92013-01-10 18:38:46 -08002022 final int height = provider.getVerticalUnitSize();
2023 final int margin = provider.getHorizontaUnitMargin();
2024 final int width = provider.getHorizontalUnitSize();
Romain Guy672433d2013-01-04 19:05:13 -08002025
2026 int x = 0;
2027 int count = 0;
2028 int current = 0;
2029
Romain Guy48ef4a92013-01-10 18:38:46 -08002030 final float[] data = provider.getData();
2031 final int elementCount = provider.getElementCount();
2032 final int graphType = provider.getGraphType();
2033
2034 int totalCount = provider.getFrameCount() * elementCount;
2035 if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
2036 totalCount -= elementCount;
2037 }
2038
2039 for (int i = 0; i < totalCount; i += elementCount) {
2040 if (data[i] < 0.0f) break;
Romain Guy672433d2013-01-04 19:05:13 -08002041
2042 int index = count * 4;
Romain Guy48ef4a92013-01-10 18:38:46 -08002043 if (i == provider.getCurrentFrame() * elementCount) current = index;
Romain Guy672433d2013-01-04 19:05:13 -08002044
Romain Guy98e4a522013-01-07 10:58:34 -08002045 x += margin;
2046 int x2 = x + width;
Romain Guy672433d2013-01-04 19:05:13 -08002047
2048 int y2 = mHeight;
Romain Guy48ef4a92013-01-10 18:38:46 -08002049 int y1 = (int) (y2 - data[i] * height);
Romain Guy672433d2013-01-04 19:05:13 -08002050
Romain Guy48ef4a92013-01-10 18:38:46 -08002051 switch (graphType) {
2052 case GraphDataProvider.GRAPH_TYPE_BARS: {
2053 for (int j = 0; j < elementCount; j++) {
2054 //noinspection MismatchedReadAndWriteOfArray
2055 final float[] r = mProfileShapes[j];
2056 r[index] = x;
2057 r[index + 1] = y1;
2058 r[index + 2] = x2;
2059 r[index + 3] = y2;
Romain Guy672433d2013-01-04 19:05:13 -08002060
Romain Guy48ef4a92013-01-10 18:38:46 -08002061 y2 = y1;
2062 if (j < elementCount - 1) {
2063 y1 = (int) (y2 - data[i + j + 1] * height);
2064 }
2065 }
2066 } break;
2067 case GraphDataProvider.GRAPH_TYPE_LINES: {
2068 for (int j = 0; j < elementCount; j++) {
2069 //noinspection MismatchedReadAndWriteOfArray
2070 final float[] r = mProfileShapes[j];
2071 r[index] = (x + x2) * 0.5f;
2072 r[index + 1] = index == 0 ? y1 : r[index - 1];
2073 r[index + 2] = r[index] + width;
2074 r[index + 3] = y1;
Romain Guy672433d2013-01-04 19:05:13 -08002075
Romain Guy48ef4a92013-01-10 18:38:46 -08002076 y2 = y1;
2077 if (j < elementCount - 1) {
2078 y1 = (int) (y2 - data[i + j + 1] * height);
2079 }
2080 }
2081 } break;
2082 }
Romain Guy672433d2013-01-04 19:05:13 -08002083
Romain Guy672433d2013-01-04 19:05:13 -08002084
Romain Guy98e4a522013-01-07 10:58:34 -08002085 x += width;
Romain Guy672433d2013-01-04 19:05:13 -08002086 count++;
2087 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002088
Romain Guy98e4a522013-01-07 10:58:34 -08002089 x += margin;
Romain Guy672433d2013-01-04 19:05:13 -08002090
Romain Guy48ef4a92013-01-10 18:38:46 -08002091 drawGraph(graphType, count);
2092 drawCurrentFrame(graphType, current);
2093 drawThreshold(x, height);
Romain Guy672433d2013-01-04 19:05:13 -08002094 }
2095 }
2096
Romain Guy48ef4a92013-01-10 18:38:46 -08002097 private void drawGraph(int graphType, int count) {
2098 for (int i = 0; i < mProfileShapes.length; i++) {
2099 mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
2100 switch (graphType) {
2101 case GraphDataProvider.GRAPH_TYPE_BARS:
Chris Craik2af46352012-11-26 18:30:17 -08002102 mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
Romain Guy48ef4a92013-01-10 18:38:46 -08002103 break;
2104 case GraphDataProvider.GRAPH_TYPE_LINES:
2105 mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
2106 break;
Romain Guy672433d2013-01-04 19:05:13 -08002107 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002108 }
2109 }
2110
2111 private void drawCurrentFrame(int graphType, int index) {
2112 if (index >= 0) {
2113 mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
2114 switch (graphType) {
2115 case GraphDataProvider.GRAPH_TYPE_BARS:
2116 mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
2117 mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
2118 mProfilePaint);
2119 break;
2120 case GraphDataProvider.GRAPH_TYPE_LINES:
2121 mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
2122 mProfileShapes[2][index], mHeight, mProfilePaint);
2123 break;
2124 }
2125 }
2126 }
2127
2128 private void drawThreshold(int x, int height) {
2129 float threshold = mDebugDataProvider.getThreshold();
2130 if (threshold > 0.0f) {
2131 mDebugDataProvider.setupThresholdPaint(mProfilePaint);
2132 int y = (int) (mHeight - threshold * height);
2133 mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
2134 }
2135 }
2136
2137 private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
2138 if (mProfileShapes == null) {
2139 final int elementCount = provider.getElementCount();
2140 final int frameCount = provider.getFrameCount();
2141
2142 mProfileShapes = new float[elementCount][];
2143 for (int i = 0; i < elementCount; i++) {
2144 mProfileShapes[i] = new float[frameCount * 4];
2145 }
2146
Romain Guy672433d2013-01-04 19:05:13 -08002147 mProfilePaint = new Paint();
2148 }
Romain Guy98e4a522013-01-07 10:58:34 -08002149
Romain Guy48ef4a92013-01-10 18:38:46 -08002150 mProfilePaint.reset();
2151 if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
2152 mProfilePaint.setAntiAlias(true);
2153 }
2154
Romain Guy98e4a522013-01-07 10:58:34 -08002155 if (mDisplayMetrics == null) {
2156 mDisplayMetrics = new DisplayMetrics();
2157 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002158
Romain Guy98e4a522013-01-07 10:58:34 -08002159 attachInfo.mDisplay.getMetrics(mDisplayMetrics);
Romain Guy48ef4a92013-01-10 18:38:46 -08002160 provider.prepare(mDisplayMetrics);
Romain Guy672433d2013-01-04 19:05:13 -08002161 }
2162
2163 @Override
Romain Guy67f27952010-12-07 20:09:23 -08002164 void destroy(boolean full) {
Romain Guyb8c0de22010-12-13 14:42:34 -08002165 try {
2166 super.destroy(full);
2167 } finally {
2168 if (full && mGlCanvas != null) {
2169 mGlCanvas = null;
2170 }
Romain Guy67f27952010-12-07 20:09:23 -08002171 }
2172 }
2173
2174 @Override
Romain Guy11cb6422012-09-21 00:39:43 -07002175 void pushLayerUpdate(HardwareLayer layer) {
2176 mGlCanvas.pushLayerUpdate(layer);
2177 }
2178
2179 @Override
Romain Guye93482f2013-06-17 13:14:51 -07002180 void cancelLayerUpdate(HardwareLayer layer) {
2181 mGlCanvas.cancelLayerUpdate(layer);
2182 }
2183
2184 @Override
Romain Guy40543602013-06-12 15:31:28 -07002185 void flushLayerUpdates() {
2186 mGlCanvas.flushLayerUpdates();
2187 }
2188
2189 @Override
Romain Guy13631f32012-01-30 17:41:55 -08002190 public DisplayList createDisplayList(String name) {
2191 return new GLES20DisplayList(name);
Romain Guyb051e892010-09-28 19:09:36 -07002192 }
Romain Guyaa6c24c2011-04-28 18:40:04 -07002193
2194 @Override
Romain Guya9489272011-06-22 20:58:11 -07002195 HardwareLayer createHardwareLayer(boolean isOpaque) {
2196 return new GLES20TextureLayer(isOpaque);
Romain Guyaa6c24c2011-04-28 18:40:04 -07002197 }
2198
Romain Guy6c319ca2011-01-11 14:29:25 -08002199 @Override
Romain Guy52036b12013-02-14 18:03:37 -08002200 public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07002201 return new GLES20RenderLayer(width, height, isOpaque);
2202 }
2203
2204 @Override
Romain Guy78dd96d2013-05-03 14:24:16 -07002205 void countOverdraw(HardwareCanvas canvas) {
2206 ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
2207 }
2208
2209 @Override
2210 float getOverdraw(HardwareCanvas canvas) {
2211 return ((GLES20Canvas) canvas).getOverdraw();
2212 }
2213
2214 @Override
Romain Guy52036b12013-02-14 18:03:37 -08002215 public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07002216 return ((GLES20TextureLayer) layer).getSurfaceTexture();
2217 }
2218
Romain Guy6d7475d2011-07-27 16:28:21 -07002219 @Override
Jamie Gennis2af35242012-04-05 11:44:30 -07002220 void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
2221 ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
2222 }
2223
2224 @Override
Romain Guy1ac47652012-04-11 18:15:20 -07002225 boolean safelyRun(Runnable action) {
Romain Guycc6b7caf2013-06-24 19:19:21 -07002226 boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
Romain Guy31f2c2e2011-11-21 10:55:41 -08002227
Romain Guy1ac47652012-04-11 18:15:20 -07002228 if (needsContext) {
2229 Gl20RendererEglContext managedContext =
2230 (Gl20RendererEglContext) sEglContextStorage.get();
2231 if (managedContext == null) return false;
2232 usePbufferSurface(managedContext.getContext());
2233 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002234
Romain Guy1ac47652012-04-11 18:15:20 -07002235 try {
2236 action.run();
2237 } finally {
Jesse Hall0872b372012-04-02 12:22:51 -07002238 if (needsContext) {
2239 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
2240 EGL_NO_SURFACE, EGL_NO_CONTEXT);
2241 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002242 }
Romain Guy1ac47652012-04-11 18:15:20 -07002243
2244 return true;
2245 }
2246
2247 @Override
Romain Guybd17bd32012-10-23 19:17:15 -07002248 void destroyLayers(final View view) {
2249 if (view != null) {
2250 safelyRun(new Runnable() {
2251 @Override
2252 public void run() {
2253 if (mCanvas != null) {
2254 mCanvas.clearLayerUpdates();
2255 }
2256 destroyHardwareLayer(view);
2257 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
2258 }
2259 });
2260 }
2261 }
2262
2263 private static void destroyHardwareLayer(View view) {
2264 view.destroyLayer(true);
2265
2266 if (view instanceof ViewGroup) {
2267 ViewGroup group = (ViewGroup) view;
2268
2269 int count = group.getChildCount();
2270 for (int i = 0; i < count; i++) {
2271 destroyHardwareLayer(group.getChildAt(i));
2272 }
2273 }
2274 }
2275
2276 @Override
Romain Guy1ac47652012-04-11 18:15:20 -07002277 void destroyHardwareResources(final View view) {
2278 if (view != null) {
2279 safelyRun(new Runnable() {
2280 @Override
2281 public void run() {
Chet Haase6a2d17f2012-09-30 12:14:13 -07002282 if (mCanvas != null) {
2283 mCanvas.clearLayerUpdates();
2284 }
Romain Guy1ac47652012-04-11 18:15:20 -07002285 destroyResources(view);
2286 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
2287 }
2288 });
2289 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002290 }
Romain Guy244ada12012-03-28 16:41:26 -07002291
Romain Guy31f2c2e2011-11-21 10:55:41 -08002292 private static void destroyResources(View view) {
2293 view.destroyHardwareResources();
2294
2295 if (view instanceof ViewGroup) {
2296 ViewGroup group = (ViewGroup) view;
2297
2298 int count = group.getChildCount();
2299 for (int i = 0; i < count; i++) {
2300 destroyResources(group.getChildAt(i));
2301 }
2302 }
2303 }
Romain Guy6d7475d2011-07-27 16:28:21 -07002304
2305 static HardwareRenderer create(boolean translucent) {
2306 if (GLES20Canvas.isAvailable()) {
2307 return new Gl20Renderer(translucent);
2308 }
2309 return null;
2310 }
2311
Romain Guy19f86e82012-04-23 15:19:07 -07002312 static void startTrimMemory(int level) {
Romain Guy912a7b32011-07-26 18:57:28 -07002313 if (sEgl == null || sEglConfig == null) return;
2314
Romain Guy5d6999e2012-03-22 19:15:04 -07002315 Gl20RendererEglContext managedContext =
2316 (Gl20RendererEglContext) sEglContextStorage.get();
Romain Guy912a7b32011-07-26 18:57:28 -07002317 // We do not have OpenGL objects
Dianne Hackborn717a25d2011-11-15 18:59:59 -08002318 if (managedContext == null) {
Romain Guy912a7b32011-07-26 18:57:28 -07002319 return;
2320 } else {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08002321 usePbufferSurface(managedContext.getContext());
Romain Guye3924992010-06-10 18:51:21 -07002322 }
Romain Guy912a7b32011-07-26 18:57:28 -07002323
Dianne Hackborn27ff9132012-03-06 14:57:58 -08002324 if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
2325 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
2326 } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
2327 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
Romain Guybdf76092011-07-18 15:00:43 -07002328 }
Romain Guy19f86e82012-04-23 15:19:07 -07002329 }
Jesse Hall0872b372012-04-02 12:22:51 -07002330
Romain Guy19f86e82012-04-23 15:19:07 -07002331 static void endTrimMemory() {
2332 if (sEgl != null && sEglDisplay != null) {
2333 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
2334 }
Romain Guybdf76092011-07-18 15:00:43 -07002335 }
Romain Guy8ff6b9e2011-11-09 20:10:18 -08002336
2337 private static void usePbufferSurface(EGLContext eglContext) {
2338 synchronized (sPbufferLock) {
2339 // Create a temporary 1x1 pbuffer so we have a context
2340 // to clear our OpenGL objects
2341 if (sPbuffer == null) {
2342 sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
2343 EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
2344 });
2345 }
2346 }
2347 sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
2348 }
Romain Guye3924992010-06-10 18:51:21 -07002349 }
Romain Guy2d614592010-06-09 18:21:37 -07002350}