blob: d9e4600d42db597831df9a814470a666f371b474 [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;
Romain Guy8ff6b9e2011-11-09 20:10:18 -080037import com.google.android.gles_jni.EGLImpl;
Romain Guy2d614592010-06-09 18:21:37 -070038
39import javax.microedition.khronos.egl.EGL10;
40import javax.microedition.khronos.egl.EGL11;
41import javax.microedition.khronos.egl.EGLConfig;
42import javax.microedition.khronos.egl.EGLContext;
43import javax.microedition.khronos.egl.EGLDisplay;
44import javax.microedition.khronos.egl.EGLSurface;
Romain Guye3924992010-06-10 18:51:21 -070045import javax.microedition.khronos.opengles.GL;
Romain Guy2d614592010-06-09 18:21:37 -070046
Romain Guya9582652011-11-10 14:20:10 -080047import java.io.File;
Romain Guya676ad72012-02-13 17:47:10 -080048import java.io.PrintWriter;
Romain Guy77e67cf2012-06-19 16:38:50 -070049import java.util.concurrent.locks.ReentrantLock;
Romain Guya9582652011-11-10 14:20:10 -080050
Romain Guy484c7192011-07-25 11:56:33 -070051import static javax.microedition.khronos.egl.EGL10.*;
52
Romain Guy2d614592010-06-09 18:21:37 -070053/**
Romain Guy8d4aeb72013-02-12 16:08:55 -080054 * Interface for rendering a view hierarchy using hardware acceleration.
Romain Guy52036b12013-02-14 18:03:37 -080055 *
Romain Guy2d614592010-06-09 18:21:37 -070056 * @hide
57 */
Romain Guy61c8c9c2010-08-09 20:48:09 -070058public abstract class HardwareRenderer {
Romain Guy4f6aff32011-01-12 16:21:41 -080059 static final String LOG_TAG = "HardwareRenderer";
Romain Guyfb8b7632010-08-23 21:05:08 -070060
Romain Guy52339202010-09-03 16:04:46 -070061 /**
Romain Guya9582652011-11-10 14:20:10 -080062 * Name of the file that holds the shaders cache.
63 */
64 private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
65
66 /**
Romain Guy7d7b5492011-01-24 16:33:45 -080067 * Turn on to only refresh the parts of the screen that need updating.
Romain Guy069ea0e2011-02-08 12:24:52 -080068 * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
Romain Guy52036b12013-02-14 18:03:37 -080069 * must also have the value "true".
Romain Guy7d7b5492011-01-24 16:33:45 -080070 */
Romain Guy52036b12013-02-14 18:03:37 -080071 static final boolean RENDER_DIRTY_REGIONS = true;
Romain Guy7d7b5492011-01-24 16:33:45 -080072
73 /**
Romain Guy069ea0e2011-02-08 12:24:52 -080074 * System property used to enable or disable dirty regions invalidation.
75 * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
76 * The default value of this property is assumed to be true.
77 *
78 * Possible values:
79 * "true", to enable partial invalidates
80 * "false", to disable partial invalidates
81 */
Romain Guy4b8c4f82012-04-27 15:48:35 -070082 static final String RENDER_DIRTY_REGIONS_PROPERTY = "debug.hwui.render_dirty_regions";
Romain Guy069ea0e2011-02-08 12:24:52 -080083
84 /**
Romain Guya676ad72012-02-13 17:47:10 -080085 * System property used to enable or disable hardware rendering profiling.
86 * The default value of this property is assumed to be false.
Chet Haase09280602012-04-03 16:15:34 -070087 *
Romain Guya676ad72012-02-13 17:47:10 -080088 * When profiling is enabled, the adb shell dumpsys gfxinfo command will
89 * output extra information about the time taken to execute by the last
90 * frames.
91 *
92 * Possible values:
93 * "true", to enable profiling
Romain Guy48ef4a92013-01-10 18:38:46 -080094 * "visual_bars", to enable profiling and visualize the results on screen
95 * "visual_lines", to enable profiling and visualize the results on screen
Romain Guya676ad72012-02-13 17:47:10 -080096 * "false", to disable profiling
Romain Guy672433d2013-01-04 19:05:13 -080097 *
Romain Guy48ef4a92013-01-10 18:38:46 -080098 * @see #PROFILE_PROPERTY_VISUALIZE_BARS
99 * @see #PROFILE_PROPERTY_VISUALIZE_LINES
Romain Guya4fef022013-01-07 11:18:38 -0800100 *
Romain Guy4b8c4f82012-04-27 15:48:35 -0700101 * @hide
Romain Guya676ad72012-02-13 17:47:10 -0800102 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700103 public static final String PROFILE_PROPERTY = "debug.hwui.profile";
Romain Guya676ad72012-02-13 17:47:10 -0800104
105 /**
Romain Guya4fef022013-01-07 11:18:38 -0800106 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
Romain Guy48ef4a92013-01-10 18:38:46 -0800107 * value, profiling data will be visualized on screen as a bar chart.
Romain Guy672433d2013-01-04 19:05:13 -0800108 *
109 * @hide
110 */
Romain Guy48ef4a92013-01-10 18:38:46 -0800111 public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars";
112
113 /**
114 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
115 * value, profiling data will be visualized on screen as a line chart.
116 *
117 * @hide
118 */
119 public static final String PROFILE_PROPERTY_VISUALIZE_LINES = "visual_lines";
Romain Guy672433d2013-01-04 19:05:13 -0800120
121 /**
Chet Haase09280602012-04-03 16:15:34 -0700122 * System property used to specify the number of frames to be used
123 * when doing hardware rendering profiling.
124 * The default value of this property is #PROFILE_MAX_FRAMES.
125 *
126 * When profiling is enabled, the adb shell dumpsys gfxinfo command will
127 * output extra information about the time taken to execute by the last
128 * frames.
129 *
130 * Possible values:
131 * "60", to set the limit of frames to 60
132 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700133 static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes";
Chet Haase09280602012-04-03 16:15:34 -0700134
135 /**
Romain Guy484c7192011-07-25 11:56:33 -0700136 * System property used to debug EGL configuration choice.
137 *
138 * Possible values:
Romain Guy484c7192011-07-25 11:56:33 -0700139 * "choice", print the chosen configuration only
140 * "all", print all possible configurations
141 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700142 static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config";
Romain Guy484c7192011-07-25 11:56:33 -0700143
144 /**
Romain Guy7d7b5492011-01-24 16:33:45 -0800145 * Turn on to draw dirty regions every other frame.
Romain Guyb04f7e92012-02-15 12:36:54 -0800146 *
147 * Possible values:
148 * "true", to enable dirty regions debugging
149 * "false", to disable dirty regions debugging
Romain Guy4b8c4f82012-04-27 15:48:35 -0700150 *
151 * @hide
Romain Guy7d7b5492011-01-24 16:33:45 -0800152 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700153 public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions";
Romain Guy4ff0cf42012-08-06 14:51:10 -0700154
155 /**
156 * Turn on to flash hardware layers when they update.
157 *
158 * Possible values:
159 * "true", to enable hardware layers updates debugging
160 * "false", to disable hardware layers updates debugging
161 *
162 * @hide
163 */
164 public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY =
165 "debug.hwui.show_layers_updates";
166
Romain Guy7d7b5492011-01-24 16:33:45 -0800167 /**
Romain Guy78dd96d2013-05-03 14:24:16 -0700168 * Controls overdraw debugging.
Romain Guy7c450aa2012-09-21 19:15:00 -0700169 *
170 * Possible values:
Romain Guy7c450aa2012-09-21 19:15:00 -0700171 * "false", to disable overdraw debugging
Romain Guy78dd96d2013-05-03 14:24:16 -0700172 * "show", to show overdraw areas on screen
173 * "count", to display an overdraw counter
Romain Guy7c450aa2012-09-21 19:15:00 -0700174 *
175 * @hide
176 */
Romain Guy78dd96d2013-05-03 14:24:16 -0700177 public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw";
178
179 /**
180 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
181 * value, overdraw will be shown on screen by coloring pixels.
182 *
183 * @hide
184 */
185 public static final String OVERDRAW_PROPERTY_SHOW = "show";
186
187 /**
188 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
189 * value, an overdraw counter will be shown on screen.
190 *
191 * @hide
192 */
193 public static final String OVERDRAW_PROPERTY_COUNT = "count";
Romain Guy7c450aa2012-09-21 19:15:00 -0700194
195 /**
Romain Guy08bca882013-02-25 16:21:30 -0800196 * Turn on to debug non-rectangular clip operations.
197 *
198 * Possible values:
199 * "hide", to disable this debug mode
200 * "highlight", highlight drawing commands tested against a non-rectangular clip
201 * "stencil", renders the clip region on screen when set
202 *
203 * @hide
204 */
205 public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY =
206 "debug.hwui.show_non_rect_clip";
207
208 /**
Romain Guy52339202010-09-03 16:04:46 -0700209 * A process can set this flag to false to prevent the use of hardware
210 * rendering.
211 *
212 * @hide
213 */
214 public static boolean sRendererDisabled = false;
215
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700216 /**
217 * Further hardware renderer disabling for the system process.
218 *
219 * @hide
220 */
221 public static boolean sSystemRendererDisabled = false;
222
Romain Guya676ad72012-02-13 17:47:10 -0800223 /**
224 * Number of frames to profile.
225 */
Romain Guya21f8772012-05-07 10:20:52 -0700226 private static final int PROFILE_MAX_FRAMES = 128;
Romain Guya676ad72012-02-13 17:47:10 -0800227
228 /**
229 * Number of floats per profiled frame.
230 */
231 private static final int PROFILE_FRAME_DATA_COUNT = 3;
232
Romain Guy2d614592010-06-09 18:21:37 -0700233 private boolean mEnabled;
234 private boolean mRequested = true;
235
236 /**
Romain Guy67f27952010-12-07 20:09:23 -0800237 * Invoke this method to disable hardware rendering in the current process.
Romain Guy52339202010-09-03 16:04:46 -0700238 *
239 * @hide
240 */
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700241 public static void disable(boolean system) {
Romain Guy52339202010-09-03 16:04:46 -0700242 sRendererDisabled = true;
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700243 if (system) {
244 sSystemRendererDisabled = true;
245 }
Romain Guy52339202010-09-03 16:04:46 -0700246 }
247
248 /**
Romain Guy61c8c9c2010-08-09 20:48:09 -0700249 * Indicates whether hardware acceleration is available under any form for
250 * the view hierarchy.
251 *
252 * @return True if the view hierarchy can potentially be hardware accelerated,
253 * false otherwise
254 */
255 public static boolean isAvailable() {
256 return GLES20Canvas.isAvailable();
257 }
258
259 /**
Romain Guy2d614592010-06-09 18:21:37 -0700260 * Destroys the hardware rendering context.
Romain Guy4caa4ed2010-08-25 14:46:24 -0700261 *
262 * @param full If true, destroys all associated resources.
Romain Guy2d614592010-06-09 18:21:37 -0700263 */
Romain Guy4caa4ed2010-08-25 14:46:24 -0700264 abstract void destroy(boolean full);
Romain Guy2d614592010-06-09 18:21:37 -0700265
266 /**
267 * Initializes the hardware renderer for the specified surface.
268 *
Romain Guy786fc932012-07-24 16:24:56 -0700269 * @param surface The surface to hardware accelerate
Romain Guy2d614592010-06-09 18:21:37 -0700270 *
271 * @return True if the initialization was successful, false otherwise.
272 */
Romain Guy786fc932012-07-24 16:24:56 -0700273 abstract boolean initialize(Surface surface) throws Surface.OutOfResourcesException;
Romain Guy2a83f002011-01-18 18:28:21 -0800274
275 /**
276 * Updates the hardware renderer for the specified surface.
Romain Guy786fc932012-07-24 16:24:56 -0700277 *
278 * @param surface The surface to hardware accelerate
Romain Guy2a83f002011-01-18 18:28:21 -0800279 */
Romain Guy786fc932012-07-24 16:24:56 -0700280 abstract void updateSurface(Surface surface) throws Surface.OutOfResourcesException;
Romain Guy2d614592010-06-09 18:21:37 -0700281
282 /**
Romain Guy31f2c2e2011-11-21 10:55:41 -0800283 * Destroys the layers used by the specified view hierarchy.
Romain Guy6d7475d2011-07-27 16:28:21 -0700284 *
285 * @param view The root of the view hierarchy
286 */
287 abstract void destroyLayers(View view);
288
289 /**
Romain Guy31f2c2e2011-11-21 10:55:41 -0800290 * Destroys all hardware rendering resources associated with the specified
291 * view hierarchy.
292 *
293 * @param view The root of the view hierarchy
294 */
295 abstract void destroyHardwareResources(View view);
296
297 /**
Romain Guy03985752011-07-11 15:33:51 -0700298 * This method should be invoked whenever the current hardware renderer
Romain Guycf15efb2011-08-02 12:59:32 -0700299 * context should be reset.
Romain Guy786fc932012-07-24 16:24:56 -0700300 *
301 * @param surface The surface to hardware accelerate
Romain Guy7e1160e2011-07-08 15:49:50 -0700302 */
Romain Guy786fc932012-07-24 16:24:56 -0700303 abstract void invalidate(Surface surface);
Romain Guy03985752011-07-11 15:33:51 -0700304
305 /**
306 * This method should be invoked to ensure the hardware renderer is in
307 * valid state (for instance, to ensure the correct EGL context is bound
308 * to the current thread.)
309 *
310 * @return true if the renderer is now valid, false otherwise
311 */
312 abstract boolean validate();
Romain Guy7e1160e2011-07-08 15:49:50 -0700313
314 /**
Romain Guy1ac47652012-04-11 18:15:20 -0700315 * This method ensures the hardware renderer is in a valid state
316 * before executing the specified action.
317 *
318 * This method will attempt to set a valid state even if the window
319 * the renderer is attached to was destroyed.
320 *
321 * @return true if the action was run
322 */
323 abstract boolean safelyRun(Runnable action);
324
325 /**
Romain Guy7e1160e2011-07-08 15:49:50 -0700326 * Setup the hardware renderer for drawing. This is called whenever the
327 * size of the target surface changes or when the surface is first created.
Romain Guy2d614592010-06-09 18:21:37 -0700328 *
329 * @param width Width of the drawing surface.
330 * @param height Height of the drawing surface.
Romain Guy2d614592010-06-09 18:21:37 -0700331 */
Romain Guyfb8b7632010-08-23 21:05:08 -0700332 abstract void setup(int width, int height);
Romain Guy2d614592010-06-09 18:21:37 -0700333
Romain Guy069ea0e2011-02-08 12:24:52 -0800334 /**
Chet Haase40e03832011-10-06 08:34:13 -0700335 * Gets the current width of the surface. This is the width that the surface
336 * was last set to in a call to {@link #setup(int, int)}.
337 *
338 * @return the current width of the surface
339 */
340 abstract int getWidth();
341
342 /**
343 * Gets the current height of the surface. This is the height that the surface
344 * was last set to in a call to {@link #setup(int, int)}.
345 *
346 * @return the current width of the surface
347 */
348 abstract int getHeight();
349
350 /**
Chet Haase08837c22011-11-28 11:53:21 -0800351 * Gets the current canvas associated with this HardwareRenderer.
352 *
353 * @return the current HardwareCanvas
354 */
355 abstract HardwareCanvas getCanvas();
356
357 /**
Romain Guya676ad72012-02-13 17:47:10 -0800358 * Outputs extra debugging information in the specified file descriptor.
359 * @param pw
360 */
361 abstract void dumpGfxInfo(PrintWriter pw);
Michael Jurkaa3fabff2012-03-28 17:22:29 +0200362
363 /**
364 * Outputs the total number of frames rendered (used for fps calculations)
365 *
366 * @return the number of frames rendered
367 */
368 abstract long getFrameCount();
369
Romain Guya676ad72012-02-13 17:47:10 -0800370 /**
Romain Guy5bb3c732012-11-29 17:52:58 -0800371 * Loads system properties used by the renderer. This method is invoked
372 * whenever system properties are modified. Implementations can use this
373 * to trigger live updates of the renderer based on properties.
374 *
375 * @param surface The surface to update with the new properties.
376 * Can be null.
377 *
378 * @return True if a property has changed.
379 */
380 abstract boolean loadSystemProperties(Surface surface);
381
382 private static native boolean nLoadProperties();
383
384 /**
Romain Guya9582652011-11-10 14:20:10 -0800385 * Sets the directory to use as a persistent storage for hardware rendering
386 * resources.
387 *
388 * @param cacheDir A directory the current process can write to
Romain Guy52036b12013-02-14 18:03:37 -0800389 *
390 * @hide
Romain Guya9582652011-11-10 14:20:10 -0800391 */
392 public static void setupDiskCache(File cacheDir) {
393 nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
394 }
395
396 private static native void nSetupShadersDiskCache(String cacheFile);
397
398 /**
Jamie Gennisb335fad2012-01-15 18:54:57 -0800399 * Notifies EGL that the frame is about to be rendered.
Romain Guy76878822012-03-30 14:54:22 -0700400 * @param size
Jamie Gennisb335fad2012-01-15 18:54:57 -0800401 */
Romain Guy672433d2013-01-04 19:05:13 -0800402 static void beginFrame(int[] size) {
Romain Guy76878822012-03-30 14:54:22 -0700403 nBeginFrame(size);
Jamie Gennisb335fad2012-01-15 18:54:57 -0800404 }
405
Romain Guy76878822012-03-30 14:54:22 -0700406 private static native void nBeginFrame(int[] size);
Jamie Gennisb335fad2012-01-15 18:54:57 -0800407
408 /**
Romain Guye9bc11f2013-05-23 12:47:26 -0700409 * Returns the current system time according to the renderer.
410 * This method is used for debugging only and should not be used
411 * as a clock.
412 */
413 static long getSystemTime() {
414 return nGetSystemTime();
415 }
416
417 private static native long nGetSystemTime();
418
419 /**
Romain Guy244ada12012-03-28 16:41:26 -0700420 * Preserves the back buffer of the current surface after a buffer swap.
421 * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
422 * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
423 * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
424 *
425 * @return True if the swap behavior was successfully changed,
426 * false otherwise.
427 */
428 static boolean preserveBackBuffer() {
429 return nPreserveBackBuffer();
430 }
431
432 private static native boolean nPreserveBackBuffer();
433
434 /**
435 * Indicates whether the current surface preserves its back buffer
436 * after a buffer swap.
437 *
438 * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
439 * false otherwise
440 */
441 static boolean isBackBufferPreserved() {
442 return nIsBackBufferPreserved();
443 }
444
445 private static native boolean nIsBackBufferPreserved();
446
447 /**
Romain Guy11cb6422012-09-21 00:39:43 -0700448 * Indicates that the specified hardware layer needs to be updated
449 * as soon as possible.
450 *
451 * @param layer The hardware layer that needs an update
Romain Guy40543602013-06-12 15:31:28 -0700452 *
453 * @see #flushLayerUpdates()
Romain Guye93482f2013-06-17 13:14:51 -0700454 * @see #cancelLayerUpdate(HardwareLayer)
Romain Guy11cb6422012-09-21 00:39:43 -0700455 */
456 abstract void pushLayerUpdate(HardwareLayer layer);
457
458 /**
Romain Guye93482f2013-06-17 13:14:51 -0700459 * Cancels a queued layer update. If the specified layer was not
460 * queued for update, this method has no effect.
461 *
462 * @param layer The layer whose update to cancel
463 *
464 * @see #pushLayerUpdate(HardwareLayer)
465 */
466 abstract void cancelLayerUpdate(HardwareLayer layer);
467
468 /**
Romain Guy40543602013-06-12 15:31:28 -0700469 * Forces all enqueued layer updates to be executed immediately.
470 *
471 * @see #pushLayerUpdate(HardwareLayer)
472 */
473 abstract void flushLayerUpdates();
474
475 /**
Romain Guy069ea0e2011-02-08 12:24:52 -0800476 * Interface used to receive callbacks whenever a view is drawn by
477 * a hardware renderer instance.
478 */
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800479 interface HardwareDrawCallbacks {
Romain Guy069ea0e2011-02-08 12:24:52 -0800480 /**
481 * Invoked before a view is drawn by a hardware renderer.
Romain Guy96885eb2013-03-26 15:05:58 -0700482 * This method can be used to apply transformations to the
483 * canvas but no drawing command should be issued.
Romain Guy069ea0e2011-02-08 12:24:52 -0800484 *
485 * @param canvas The Canvas used to render the view.
486 */
Romain Guy7d70fbf2011-05-24 17:40:25 -0700487 void onHardwarePreDraw(HardwareCanvas canvas);
Romain Guy069ea0e2011-02-08 12:24:52 -0800488
489 /**
490 * Invoked after a view is drawn by a hardware renderer.
Romain Guy96885eb2013-03-26 15:05:58 -0700491 * It is safe to invoke drawing commands from this method.
Romain Guy069ea0e2011-02-08 12:24:52 -0800492 *
493 * @param canvas The Canvas used to render the view.
494 */
Romain Guy7d70fbf2011-05-24 17:40:25 -0700495 void onHardwarePostDraw(HardwareCanvas canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800496 }
497
Romain Guy2d614592010-06-09 18:21:37 -0700498 /**
499 * Draws the specified view.
Romain Guy7d7b5492011-01-24 16:33:45 -0800500 *
Romain Guy2d614592010-06-09 18:21:37 -0700501 * @param view The view to draw.
502 * @param attachInfo AttachInfo tied to the specified view.
Romain Guy7d7b5492011-01-24 16:33:45 -0800503 * @param callbacks Callbacks invoked when drawing happens.
504 * @param dirty The dirty rectangle to update, can be null.
Romain Guy2d614592010-06-09 18:21:37 -0700505 */
Romain Guye55945e2013-04-04 15:26:04 -0700506 abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Romain Guy7d7b5492011-01-24 16:33:45 -0800507 Rect dirty);
Romain Guy2d614592010-06-09 18:21:37 -0700508
509 /**
Romain Guy53ca03d2010-10-08 18:55:27 -0700510 * Creates a new display list that can be used to record batches of
511 * drawing operations.
Romain Guyb051e892010-09-28 19:09:36 -0700512 *
Romain Guy52036b12013-02-14 18:03:37 -0800513 * @param name The name of the display list, used for debugging purpose. May be null.
Romain Guy13631f32012-01-30 17:41:55 -0800514 *
Romain Guy53ca03d2010-10-08 18:55:27 -0700515 * @return A new display list.
Romain Guy52036b12013-02-14 18:03:37 -0800516 *
517 * @hide
Romain Guyb051e892010-09-28 19:09:36 -0700518 */
Romain Guy13631f32012-01-30 17:41:55 -0800519 public abstract DisplayList createDisplayList(String name);
Romain Guyb051e892010-09-28 19:09:36 -0700520
521 /**
Romain Guyaa6c24c2011-04-28 18:40:04 -0700522 * Creates a new hardware layer. A hardware layer built by calling this
523 * method will be treated as a texture layer, instead of as a render target.
524 *
Romain Guya9489272011-06-22 20:58:11 -0700525 * @param isOpaque Whether the layer should be opaque or not
526 *
Romain Guyaa6c24c2011-04-28 18:40:04 -0700527 * @return A hardware layer
Jamie Gennis2af35242012-04-05 11:44:30 -0700528 */
Romain Guya9489272011-06-22 20:58:11 -0700529 abstract HardwareLayer createHardwareLayer(boolean isOpaque);
Jamie Gennis2af35242012-04-05 11:44:30 -0700530
Romain Guyaa6c24c2011-04-28 18:40:04 -0700531 /**
Romain Guy6c319ca2011-01-11 14:29:25 -0800532 * Creates a new hardware layer.
533 *
534 * @param width The minimum width of the layer
535 * @param height The minimum height of the layer
536 * @param isOpaque Whether the layer should be opaque or not
537 *
538 * @return A hardware layer
539 */
540 abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700541
542 /**
543 * Creates a new {@link SurfaceTexture} that can be used to render into the
544 * specified hardware layer.
Romain Guyaa6c24c2011-04-28 18:40:04 -0700545 *
546 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
547 *
548 * @return A {@link SurfaceTexture}
549 */
Romain Guye5e0c502011-06-15 15:18:31 -0700550 abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700551
552 /**
Jamie Gennis2af35242012-04-05 11:44:30 -0700553 * Sets the {@link android.graphics.SurfaceTexture} that will be used to
554 * render into the specified hardware layer.
555 *
556 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
557 * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer
558 */
559 abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture);
560
561 /**
Romain Guyba6be8a2012-04-23 18:22:09 -0700562 * Detaches the specified functor from the current functor execution queue.
563 *
564 * @param functor The native functor to remove from the execution queue.
565 *
566 * @see HardwareCanvas#callDrawGLFunction(int)
567 * @see #attachFunctor(android.view.View.AttachInfo, int)
568 */
569 abstract void detachFunctor(int functor);
570
571 /**
572 * Schedules the specified functor in the functors execution queue.
573 *
574 * @param attachInfo AttachInfo tied to this renderer.
575 * @param functor The native functor to insert in the execution queue.
576 *
577 * @see HardwareCanvas#callDrawGLFunction(int)
Chris Craik41ee4652012-05-31 15:05:57 -0700578 * @see #detachFunctor(int)
579 *
580 * @return true if the functor was attached successfully
Romain Guyba6be8a2012-04-23 18:22:09 -0700581 */
Chris Craik41ee4652012-05-31 15:05:57 -0700582 abstract boolean attachFunctor(View.AttachInfo attachInfo, int functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700583
584 /**
Romain Guy2d614592010-06-09 18:21:37 -0700585 * Initializes the hardware renderer for the specified surface and setup the
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700586 * renderer for drawing, if needed. This is invoked when the ViewAncestor has
Romain Guy2d614592010-06-09 18:21:37 -0700587 * potentially lost the hardware renderer. The hardware renderer should be
588 * reinitialized and setup when the render {@link #isRequested()} and
589 * {@link #isEnabled()}.
Romain Guy44d79742012-01-13 12:12:09 -0800590 *
Romain Guy2d614592010-06-09 18:21:37 -0700591 * @param width The width of the drawing surface.
592 * @param height The height of the drawing surface.
Romain Guy786fc932012-07-24 16:24:56 -0700593 * @param surface The surface to hardware accelerate
Romain Guydfab3632012-10-03 14:53:25 -0700594 *
595 * @return true if the surface was initialized, false otherwise. Returning
596 * false might mean that the surface was already initialized.
Romain Guy2d614592010-06-09 18:21:37 -0700597 */
Romain Guydfab3632012-10-03 14:53:25 -0700598 boolean initializeIfNeeded(int width, int height, Surface surface)
Romain Guy44d79742012-01-13 12:12:09 -0800599 throws Surface.OutOfResourcesException {
Romain Guy2d614592010-06-09 18:21:37 -0700600 if (isRequested()) {
601 // We lost the gl context, so recreate it.
602 if (!isEnabled()) {
Romain Guy786fc932012-07-24 16:24:56 -0700603 if (initialize(surface)) {
Romain Guyfb8b7632010-08-23 21:05:08 -0700604 setup(width, height);
Romain Guydfab3632012-10-03 14:53:25 -0700605 return true;
Romain Guy2d614592010-06-09 18:21:37 -0700606 }
607 }
Romain Guydfab3632012-10-03 14:53:25 -0700608 }
609 return false;
Romain Guy2d614592010-06-09 18:21:37 -0700610 }
611
612 /**
Romain Guyef359272013-01-31 19:07:29 -0800613 * Optional, sets the name of the renderer. Useful for debugging purposes.
614 *
615 * @param name The name of this renderer, can be null
616 */
617 abstract void setName(String name);
618
619 /**
Romain Guy2d614592010-06-09 18:21:37 -0700620 * Creates a hardware renderer using OpenGL.
621 *
622 * @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 -0700623 * @param translucent True if the surface is translucent, false otherwise
Romain Guy2d614592010-06-09 18:21:37 -0700624 *
625 * @return A hardware renderer backed by OpenGL.
626 */
Romain Guye4d01122010-06-16 18:44:05 -0700627 static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
Romain Guy2d614592010-06-09 18:21:37 -0700628 switch (glVersion) {
Romain Guye3924992010-06-10 18:51:21 -0700629 case 2:
Romain Guy16393512010-08-08 00:14:31 -0700630 return Gl20Renderer.create(translucent);
Romain Guy2d614592010-06-09 18:21:37 -0700631 }
632 throw new IllegalArgumentException("Unknown GL version: " + glVersion);
633 }
634
635 /**
Romain Guybdf76092011-07-18 15:00:43 -0700636 * Invoke this method when the system is running out of memory. This
637 * method will attempt to recover as much memory as possible, based on
638 * the specified hint.
639 *
640 * @param level Hint about the amount of memory that should be trimmed,
641 * see {@link android.content.ComponentCallbacks}
642 */
643 static void trimMemory(int level) {
Romain Guy19f86e82012-04-23 15:19:07 -0700644 startTrimMemory(level);
645 endTrimMemory();
646 }
647
648 /**
649 * Starts the process of trimming memory. Usually this call will setup
650 * hardware rendering context and reclaim memory.Extra cleanup might
651 * be required by calling {@link #endTrimMemory()}.
652 *
653 * @param level Hint about the amount of memory that should be trimmed,
654 * see {@link android.content.ComponentCallbacks}
655 */
656 static void startTrimMemory(int level) {
657 Gl20Renderer.startTrimMemory(level);
658 }
659
660 /**
661 * Finishes the process of trimming memory. This method will usually
662 * cleanup special resources used by the memory trimming process.
663 */
664 static void endTrimMemory() {
665 Gl20Renderer.endTrimMemory();
Romain Guybdf76092011-07-18 15:00:43 -0700666 }
667
668 /**
Romain Guy2d614592010-06-09 18:21:37 -0700669 * Indicates whether hardware acceleration is currently enabled.
670 *
671 * @return True if hardware acceleration is in use, false otherwise.
672 */
673 boolean isEnabled() {
674 return mEnabled;
675 }
676
677 /**
678 * Indicates whether hardware acceleration is currently enabled.
679 *
680 * @param enabled True if the hardware renderer is in use, false otherwise.
681 */
682 void setEnabled(boolean enabled) {
683 mEnabled = enabled;
684 }
685
686 /**
687 * Indicates whether hardware acceleration is currently request but not
688 * necessarily enabled yet.
689 *
690 * @return True if requested, false otherwise.
691 */
692 boolean isRequested() {
693 return mRequested;
694 }
695
696 /**
Romain Guy9745fae2010-12-08 11:39:15 -0800697 * Indicates whether hardware acceleration is currently requested but not
Romain Guy2d614592010-06-09 18:21:37 -0700698 * necessarily enabled yet.
699 *
700 * @return True to request hardware acceleration, false otherwise.
701 */
702 void setRequested(boolean requested) {
703 mRequested = requested;
704 }
705
Romain Guy48ef4a92013-01-10 18:38:46 -0800706 /**
707 * Describes a series of frames that should be drawn on screen as a graph.
708 * Each frame is composed of 1 or more elements.
709 */
710 abstract class GraphDataProvider {
711 /**
712 * Draws the graph as bars. Frame elements are stacked on top of
713 * each other.
714 */
715 public static final int GRAPH_TYPE_BARS = 0;
716 /**
717 * Draws the graph as lines. The number of series drawn corresponds
718 * to the number of elements.
719 */
720 public static final int GRAPH_TYPE_LINES = 1;
721
722 /**
723 * Returns the type of graph to render.
724 *
725 * @return {@link #GRAPH_TYPE_BARS} or {@link #GRAPH_TYPE_LINES}
726 */
727 abstract int getGraphType();
728
729 /**
730 * This method is invoked before the graph is drawn. This method
731 * can be used to compute sizes, etc.
732 *
733 * @param metrics The display metrics
734 */
735 abstract void prepare(DisplayMetrics metrics);
736
737 /**
738 * @return The size in pixels of a vertical unit.
739 */
740 abstract int getVerticalUnitSize();
741
742 /**
743 * @return The size in pixels of a horizontal unit.
744 */
745 abstract int getHorizontalUnitSize();
746
747 /**
748 * @return The size in pixels of the margin between horizontal units.
749 */
750 abstract int getHorizontaUnitMargin();
751
752 /**
753 * An optional threshold value.
754 *
755 * @return A value >= 0 to draw the threshold, a negative value
756 * to ignore it.
757 */
758 abstract float getThreshold();
759
760 /**
761 * The data to draw in the graph. The number of elements in the
762 * array must be at least {@link #getFrameCount()} * {@link #getElementCount()}.
763 * If a value is negative the following values will be ignored.
764 */
765 abstract float[] getData();
766
767 /**
768 * Returns the number of frames to render in the graph.
769 */
770 abstract int getFrameCount();
771
772 /**
773 * Returns the number of elements in each frame. This directly affects
774 * the number of series drawn in the graph.
775 */
776 abstract int getElementCount();
777
778 /**
779 * Returns the current frame, if any. If the returned value is negative
780 * the current frame is ignored.
781 */
782 abstract int getCurrentFrame();
783
784 /**
785 * Prepares the paint to draw the specified element (or series.)
786 */
787 abstract void setupGraphPaint(Paint paint, int elementIndex);
788
789 /**
790 * Prepares the paint to draw the threshold.
791 */
792 abstract void setupThresholdPaint(Paint paint);
793
794 /**
795 * Prepares the paint to draw the current frame indicator.
796 */
797 abstract void setupCurrentFramePaint(Paint paint);
798 }
799
Romain Guy2d614592010-06-09 18:21:37 -0700800 @SuppressWarnings({"deprecation"})
Romain Guye3924992010-06-10 18:51:21 -0700801 static abstract class GlRenderer extends HardwareRenderer {
Romain Guy16260e72011-09-01 14:26:11 -0700802 static final int SURFACE_STATE_ERROR = 0;
803 static final int SURFACE_STATE_SUCCESS = 1;
804 static final int SURFACE_STATE_UPDATED = 2;
Romain Guy8f3b8e32012-03-27 16:33:45 -0700805
Chris Craik65924a32012-04-05 17:52:11 -0700806 static final int FUNCTOR_PROCESS_DELAY = 4;
Romain Guy8f3b8e32012-03-27 16:33:45 -0700807
Romain Guy48ef4a92013-01-10 18:38:46 -0800808 private static final int PROFILE_DRAW_MARGIN = 0;
809 private static final int PROFILE_DRAW_WIDTH = 3;
810 private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
811 private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
812 private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
813 private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
814 private static final int PROFILE_DRAW_DP_PER_MS = 7;
815
Romain Guy78dd96d2013-05-03 14:24:16 -0700816 private static final String[] VISUALIZERS = {
817 PROFILE_PROPERTY_VISUALIZE_BARS,
818 PROFILE_PROPERTY_VISUALIZE_LINES
819 };
820
821 private static final String[] OVERDRAW = {
822 OVERDRAW_PROPERTY_SHOW,
823 OVERDRAW_PROPERTY_COUNT
824 };
825 private static final int OVERDRAW_TYPE_COUNT = 1;
826
Romain Guyfb8b7632010-08-23 21:05:08 -0700827 static EGL10 sEgl;
828 static EGLDisplay sEglDisplay;
829 static EGLConfig sEglConfig;
Romain Guy566b3ef2011-07-18 18:38:12 -0700830 static final Object[] sEglLock = new Object[0];
Chet Haase40e03832011-10-06 08:34:13 -0700831 int mWidth = -1, mHeight = -1;
Romain Guy2d614592010-06-09 18:21:37 -0700832
Romain Guy5d6999e2012-03-22 19:15:04 -0700833 static final ThreadLocal<ManagedEGLContext> sEglContextStorage
834 = new ThreadLocal<ManagedEGLContext>();
Romain Guy566b3ef2011-07-18 18:38:12 -0700835
836 EGLContext mEglContext;
837 Thread mEglThread;
Romain Guyfb8b7632010-08-23 21:05:08 -0700838
839 EGLSurface mEglSurface;
840
Romain Guye3924992010-06-10 18:51:21 -0700841 GL mGl;
Romain Guy67f27952010-12-07 20:09:23 -0800842 HardwareCanvas mCanvas;
Romain Guya676ad72012-02-13 17:47:10 -0800843
Romain Guyef359272013-01-31 19:07:29 -0800844 String mName;
845
Michael Jurkaa3fabff2012-03-28 17:22:29 +0200846 long mFrameCount;
Romain Guy7d7b5492011-01-24 16:33:45 -0800847 Paint mDebugPaint;
848
Romain Guy7e1160e2011-07-08 15:49:50 -0700849 static boolean sDirtyRegions;
850 static final boolean sDirtyRegionsRequested;
851 static {
852 String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
853 //noinspection PointlessBooleanExpression,ConstantConditions
854 sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
855 sDirtyRegionsRequested = sDirtyRegions;
856 }
857
858 boolean mDirtyRegionsEnabled;
Romain Guy9477c6e2011-12-09 12:27:21 -0800859 boolean mUpdateDirtyRegions;
860
Romain Guy5bb3c732012-11-29 17:52:58 -0800861 boolean mProfileEnabled;
Romain Guy48ef4a92013-01-10 18:38:46 -0800862 int mProfileVisualizerType = -1;
Romain Guy5bb3c732012-11-29 17:52:58 -0800863 float[] mProfileData;
864 ReentrantLock mProfileLock;
Romain Guya676ad72012-02-13 17:47:10 -0800865 int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
Romain Guy672433d2013-01-04 19:05:13 -0800866
Romain Guy48ef4a92013-01-10 18:38:46 -0800867 GraphDataProvider mDebugDataProvider;
868 float[][] mProfileShapes;
Romain Guy672433d2013-01-04 19:05:13 -0800869 Paint mProfilePaint;
870
Romain Guy5bb3c732012-11-29 17:52:58 -0800871 boolean mDebugDirtyRegions;
Romain Guy78dd96d2013-05-03 14:24:16 -0700872 int mDebugOverdraw = -1;
873 HardwareLayer mDebugOverdrawLayer;
874 Paint mDebugOverdrawPaint;
Romain Guya676ad72012-02-13 17:47:10 -0800875
Romain Guye4d01122010-06-16 18:44:05 -0700876 final int mGlVersion;
877 final boolean mTranslucent;
Romain Guye3924992010-06-10 18:51:21 -0700878
Romain Guyfb8b7632010-08-23 21:05:08 -0700879 private boolean mDestroyed;
Romain Guy566b3ef2011-07-18 18:38:12 -0700880
Romain Guycabfcc12011-03-07 18:06:46 -0800881 private final Rect mRedrawClip = new Rect();
Romain Guy8f3b8e32012-03-27 16:33:45 -0700882
Romain Guy76878822012-03-30 14:54:22 -0700883 private final int[] mSurfaceSize = new int[2];
Romain Guy8f3b8e32012-03-27 16:33:45 -0700884 private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
Romain Guyfb8b7632010-08-23 21:05:08 -0700885
Romain Guye9bc11f2013-05-23 12:47:26 -0700886 private long mDrawDelta = Long.MAX_VALUE;
887
Romain Guye4d01122010-06-16 18:44:05 -0700888 GlRenderer(int glVersion, boolean translucent) {
Romain Guye3924992010-06-10 18:51:21 -0700889 mGlVersion = glVersion;
Romain Guye4d01122010-06-16 18:44:05 -0700890 mTranslucent = translucent;
Romain Guy9ace8f52011-07-07 20:50:11 -0700891
Romain Guy5bb3c732012-11-29 17:52:58 -0800892 loadSystemProperties(null);
893 }
Romain Guya676ad72012-02-13 17:47:10 -0800894
Romain Guy5bb3c732012-11-29 17:52:58 -0800895 @Override
896 boolean loadSystemProperties(Surface surface) {
Romain Guya4fef022013-01-07 11:18:38 -0800897 boolean value;
Romain Guy5bb3c732012-11-29 17:52:58 -0800898 boolean changed = false;
899
Romain Guya4fef022013-01-07 11:18:38 -0800900 String profiling = SystemProperties.get(PROFILE_PROPERTY);
Romain Guy78dd96d2013-05-03 14:24:16 -0700901 int graphType = search(VISUALIZERS, profiling);
Romain Guy48ef4a92013-01-10 18:38:46 -0800902 value = graphType >= 0;
Romain Guya4fef022013-01-07 11:18:38 -0800903
Romain Guy48ef4a92013-01-10 18:38:46 -0800904 if (graphType != mProfileVisualizerType) {
Romain Guya4fef022013-01-07 11:18:38 -0800905 changed = true;
Romain Guy48ef4a92013-01-10 18:38:46 -0800906 mProfileVisualizerType = graphType;
Romain Guya4fef022013-01-07 11:18:38 -0800907
Romain Guy48ef4a92013-01-10 18:38:46 -0800908 mProfileShapes = null;
Romain Guya4fef022013-01-07 11:18:38 -0800909 mProfilePaint = null;
Romain Guy48ef4a92013-01-10 18:38:46 -0800910
911 if (value) {
912 mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
913 } else {
914 mDebugDataProvider = null;
915 }
Romain Guya4fef022013-01-07 11:18:38 -0800916 }
917
918 // If on-screen profiling is not enabled, we need to check whether
919 // console profiling only is enabled
920 if (!value) {
921 value = Boolean.parseBoolean(profiling);
922 }
923
Romain Guy5bb3c732012-11-29 17:52:58 -0800924 if (value != mProfileEnabled) {
925 changed = true;
926 mProfileEnabled = value;
927
928 if (mProfileEnabled) {
929 Log.d(LOG_TAG, "Profiling hardware renderer");
Romain Guy77e67cf2012-06-19 16:38:50 -0700930
Romain Guy5bb3c732012-11-29 17:52:58 -0800931 int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY,
932 PROFILE_MAX_FRAMES);
933 mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
934 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
935 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
936 }
937
938 mProfileLock = new ReentrantLock();
939 } else {
940 mProfileData = null;
941 mProfileLock = null;
Romain Guy48ef4a92013-01-10 18:38:46 -0800942 mProfileVisualizerType = -1;
Romain Guy5bb3c732012-11-29 17:52:58 -0800943 }
Romain Guy672433d2013-01-04 19:05:13 -0800944
Romain Guy666d5da2013-01-07 11:29:14 -0800945 mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
Romain Guy672433d2013-01-04 19:05:13 -0800946 }
947
Romain Guy5bb3c732012-11-29 17:52:58 -0800948 value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
949 if (value != mDebugDirtyRegions) {
950 changed = true;
951 mDebugDirtyRegions = value;
952
953 if (mDebugDirtyRegions) {
954 Log.d(LOG_TAG, "Debugging dirty regions");
955 }
Romain Guyb04f7e92012-02-15 12:36:54 -0800956 }
Romain Guy7c450aa2012-09-21 19:15:00 -0700957
Romain Guy78dd96d2013-05-03 14:24:16 -0700958 String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY);
959 int debugOverdraw = search(OVERDRAW, overdraw);
960 if (debugOverdraw != mDebugOverdraw) {
Romain Guy5bb3c732012-11-29 17:52:58 -0800961 changed = true;
Romain Guy78dd96d2013-05-03 14:24:16 -0700962 mDebugOverdraw = debugOverdraw;
963
964 if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
965 if (mDebugOverdrawLayer != null) {
966 mDebugOverdrawLayer.destroy();
967 mDebugOverdrawLayer = null;
968 mDebugOverdrawPaint = null;
969 }
970 }
Romain Guy5bb3c732012-11-29 17:52:58 -0800971 }
972
973 if (nLoadProperties()) {
974 changed = true;
975 }
976
977 return changed;
Romain Guya676ad72012-02-13 17:47:10 -0800978 }
979
Romain Guy78dd96d2013-05-03 14:24:16 -0700980 private static int search(String[] values, String value) {
981 for (int i = 0; i < values.length; i++) {
982 if (values[i].equals(value)) return i;
983 }
984 return -1;
985 }
986
Romain Guya676ad72012-02-13 17:47:10 -0800987 @Override
988 void dumpGfxInfo(PrintWriter pw) {
989 if (mProfileEnabled) {
990 pw.printf("\n\tDraw\tProcess\tExecute\n");
Romain Guy77e67cf2012-06-19 16:38:50 -0700991
992 mProfileLock.lock();
993 try {
994 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
995 if (mProfileData[i] < 0) {
996 break;
997 }
998 pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
999 mProfileData[i + 2]);
1000 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
Chet Haase09280602012-04-03 16:15:34 -07001001 }
Romain Guy77e67cf2012-06-19 16:38:50 -07001002 mProfileCurrentFrame = mProfileData.length;
1003 } finally {
1004 mProfileLock.unlock();
Romain Guya676ad72012-02-13 17:47:10 -08001005 }
1006 }
Romain Guy2d614592010-06-09 18:21:37 -07001007 }
1008
Michael Jurkaa3fabff2012-03-28 17:22:29 +02001009 @Override
1010 long getFrameCount() {
1011 return mFrameCount;
1012 }
1013
Romain Guye3924992010-06-10 18:51:21 -07001014 /**
Romain Guy02ccac62011-06-24 13:20:23 -07001015 * Indicates whether this renderer instance can track and update dirty regions.
1016 */
1017 boolean hasDirtyRegions() {
Romain Guy7e1160e2011-07-08 15:49:50 -07001018 return mDirtyRegionsEnabled;
Romain Guy02ccac62011-06-24 13:20:23 -07001019 }
1020
1021 /**
Romain Guy4caa4ed2010-08-25 14:46:24 -07001022 * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
Romain Guye3924992010-06-10 18:51:21 -07001023 * is invoked and the requested flag is turned off. The error code is
1024 * also logged as a warning.
1025 */
Romain Guyb025b9c2010-09-16 14:16:48 -07001026 void checkEglErrors() {
Romain Guy2d614592010-06-09 18:21:37 -07001027 if (isEnabled()) {
Romain Guy740ee652012-09-17 18:11:40 -07001028 checkEglErrorsForced();
1029 }
1030 }
1031
1032 private void checkEglErrorsForced() {
1033 int error = sEgl.eglGetError();
1034 if (error != EGL_SUCCESS) {
1035 // something bad has happened revert to
1036 // normal rendering.
1037 Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
1038 fallback(error != EGL11.EGL_CONTEXT_LOST);
Romain Guy2d614592010-06-09 18:21:37 -07001039 }
1040 }
Romain Guy67f27952010-12-07 20:09:23 -08001041
Romain Guy9745fae2010-12-08 11:39:15 -08001042 private void fallback(boolean fallback) {
1043 destroy(true);
1044 if (fallback) {
1045 // we'll try again if it was context lost
1046 setRequested(false);
Romain Guy3b748a42013-04-17 18:54:38 -07001047 Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
Romain Guy9745fae2010-12-08 11:39:15 -08001048 + "Switching back to software rendering.");
1049 }
1050 }
1051
Romain Guy2d614592010-06-09 18:21:37 -07001052 @Override
Romain Guy786fc932012-07-24 16:24:56 -07001053 boolean initialize(Surface surface) throws Surface.OutOfResourcesException {
Romain Guy2d614592010-06-09 18:21:37 -07001054 if (isRequested() && !isEnabled()) {
Romain Guy3b748a42013-04-17 18:54:38 -07001055 boolean contextCreated = initializeEgl();
Romain Guy786fc932012-07-24 16:24:56 -07001056 mGl = createEglSurface(surface);
Romain Guyfb8b7632010-08-23 21:05:08 -07001057 mDestroyed = false;
Romain Guye3924992010-06-10 18:51:21 -07001058
1059 if (mGl != null) {
Romain Guyfb8b7632010-08-23 21:05:08 -07001060 int err = sEgl.eglGetError();
Romain Guy484c7192011-07-25 11:56:33 -07001061 if (err != EGL_SUCCESS) {
Romain Guy4caa4ed2010-08-25 14:46:24 -07001062 destroy(true);
Romain Guye3924992010-06-10 18:51:21 -07001063 setRequested(false);
1064 } else {
Romain Guy4caa4ed2010-08-25 14:46:24 -07001065 if (mCanvas == null) {
1066 mCanvas = createCanvas();
Romain Guyef359272013-01-31 19:07:29 -08001067 mCanvas.setName(mName);
Romain Guyfb8b7632010-08-23 21:05:08 -07001068 }
Romain Guye55945e2013-04-04 15:26:04 -07001069 setEnabled(true);
Romain Guy3b748a42013-04-17 18:54:38 -07001070
1071 if (contextCreated) {
1072 initAtlas();
1073 }
Romain Guye3924992010-06-10 18:51:21 -07001074 }
1075
1076 return mCanvas != null;
1077 }
Romain Guy2d614592010-06-09 18:21:37 -07001078 }
1079 return false;
1080 }
Romain Guy2a83f002011-01-18 18:28:21 -08001081
1082 @Override
Romain Guy786fc932012-07-24 16:24:56 -07001083 void updateSurface(Surface surface) throws Surface.OutOfResourcesException {
Romain Guy2a83f002011-01-18 18:28:21 -08001084 if (isRequested() && isEnabled()) {
Romain Guy786fc932012-07-24 16:24:56 -07001085 createEglSurface(surface);
Romain Guy2a83f002011-01-18 18:28:21 -08001086 }
1087 }
Romain Guy2d614592010-06-09 18:21:37 -07001088
Romain Guy5d6999e2012-03-22 19:15:04 -07001089 abstract HardwareCanvas createCanvas();
Romain Guye3924992010-06-10 18:51:21 -07001090
Romain Guy29d23ec2011-07-25 14:42:24 -07001091 abstract int[] getConfig(boolean dirtyRegions);
1092
Romain Guy3b748a42013-04-17 18:54:38 -07001093 boolean initializeEgl() {
Romain Guy566b3ef2011-07-18 18:38:12 -07001094 synchronized (sEglLock) {
1095 if (sEgl == null && sEglConfig == null) {
1096 sEgl = (EGL10) EGLContext.getEGL();
1097
1098 // Get to the default display.
Romain Guy484c7192011-07-25 11:56:33 -07001099 sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
Romain Guy566b3ef2011-07-18 18:38:12 -07001100
Romain Guy484c7192011-07-25 11:56:33 -07001101 if (sEglDisplay == EGL_NO_DISPLAY) {
Romain Guy566b3ef2011-07-18 18:38:12 -07001102 throw new RuntimeException("eglGetDisplay failed "
Romain Guy407ec782011-08-24 17:06:58 -07001103 + GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guy566b3ef2011-07-18 18:38:12 -07001104 }
1105
1106 // We can now initialize EGL for that display
1107 int[] version = new int[2];
1108 if (!sEgl.eglInitialize(sEglDisplay, version)) {
1109 throw new RuntimeException("eglInitialize failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001110 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guy566b3ef2011-07-18 18:38:12 -07001111 }
Romain Guy740ee652012-09-17 18:11:40 -07001112
1113 checkEglErrorsForced();
1114
Romain Guy5bb3c732012-11-29 17:52:58 -08001115 sEglConfig = loadEglConfig();
Romain Guy069ea0e2011-02-08 12:24:52 -08001116 }
1117 }
Romain Guy566b3ef2011-07-18 18:38:12 -07001118
Romain Guy5d6999e2012-03-22 19:15:04 -07001119 ManagedEGLContext managedContext = sEglContextStorage.get();
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001120 mEglContext = managedContext != null ? managedContext.getContext() : null;
Romain Guy566b3ef2011-07-18 18:38:12 -07001121 mEglThread = Thread.currentThread();
1122
1123 if (mEglContext == null) {
1124 mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
Romain Guy5d6999e2012-03-22 19:15:04 -07001125 sEglContextStorage.set(createManagedContext(mEglContext));
Romain Guy3b748a42013-04-17 18:54:38 -07001126 return true;
Romain Guy566b3ef2011-07-18 18:38:12 -07001127 }
Romain Guy3b748a42013-04-17 18:54:38 -07001128
1129 return false;
Romain Guy2d614592010-06-09 18:21:37 -07001130 }
1131
Romain Guy5bb3c732012-11-29 17:52:58 -08001132 private EGLConfig loadEglConfig() {
1133 EGLConfig eglConfig = chooseEglConfig();
1134 if (eglConfig == null) {
1135 // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
1136 if (sDirtyRegions) {
1137 sDirtyRegions = false;
1138 eglConfig = chooseEglConfig();
1139 if (eglConfig == null) {
1140 throw new RuntimeException("eglConfig not initialized");
1141 }
1142 } else {
1143 throw new RuntimeException("eglConfig not initialized");
1144 }
1145 }
1146 return eglConfig;
1147 }
1148
Romain Guy5d6999e2012-03-22 19:15:04 -07001149 abstract ManagedEGLContext createManagedContext(EGLContext eglContext);
1150
Romain Guye91a9c72011-05-02 14:53:30 -07001151 private EGLConfig chooseEglConfig() {
Romain Guye91a9c72011-05-02 14:53:30 -07001152 EGLConfig[] configs = new EGLConfig[1];
Romain Guy484c7192011-07-25 11:56:33 -07001153 int[] configsCount = new int[1];
Romain Guy7e1160e2011-07-08 15:49:50 -07001154 int[] configSpec = getConfig(sDirtyRegions);
Romain Guy484c7192011-07-25 11:56:33 -07001155
1156 // Debug
Romain Guy29d23ec2011-07-25 14:42:24 -07001157 final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
Romain Guy484c7192011-07-25 11:56:33 -07001158 if ("all".equalsIgnoreCase(debug)) {
1159 sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
1160
1161 EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
1162 sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
1163 configsCount[0], configsCount);
1164
1165 for (EGLConfig config : debugConfigs) {
1166 printConfig(config);
1167 }
1168 }
1169
Romain Guye91a9c72011-05-02 14:53:30 -07001170 if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
1171 throw new IllegalArgumentException("eglChooseConfig failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001172 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guye91a9c72011-05-02 14:53:30 -07001173 } else if (configsCount[0] > 0) {
Romain Guy484c7192011-07-25 11:56:33 -07001174 if ("choice".equalsIgnoreCase(debug)) {
1175 printConfig(configs[0]);
1176 }
Romain Guye91a9c72011-05-02 14:53:30 -07001177 return configs[0];
1178 }
Romain Guy484c7192011-07-25 11:56:33 -07001179
Romain Guye91a9c72011-05-02 14:53:30 -07001180 return null;
1181 }
1182
Romain Guye979e622012-03-20 13:50:27 -07001183 private static void printConfig(EGLConfig config) {
Romain Guy484c7192011-07-25 11:56:33 -07001184 int[] value = new int[1];
1185
1186 Log.d(LOG_TAG, "EGL configuration " + config + ":");
1187
1188 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
1189 Log.d(LOG_TAG, " RED_SIZE = " + value[0]);
1190
1191 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
1192 Log.d(LOG_TAG, " GREEN_SIZE = " + value[0]);
1193
1194 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
1195 Log.d(LOG_TAG, " BLUE_SIZE = " + value[0]);
1196
1197 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
1198 Log.d(LOG_TAG, " ALPHA_SIZE = " + value[0]);
1199
1200 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
1201 Log.d(LOG_TAG, " DEPTH_SIZE = " + value[0]);
1202
1203 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
1204 Log.d(LOG_TAG, " STENCIL_SIZE = " + value[0]);
1205
Romain Guy8efca542012-10-15 18:09:49 -07001206 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value);
1207 Log.d(LOG_TAG, " SAMPLE_BUFFERS = " + value[0]);
1208
1209 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value);
1210 Log.d(LOG_TAG, " SAMPLES = " + value[0]);
1211
Romain Guy484c7192011-07-25 11:56:33 -07001212 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
Romain Guy29d23ec2011-07-25 14:42:24 -07001213 Log.d(LOG_TAG, " SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
Romain Guy8efca542012-10-15 18:09:49 -07001214
1215 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value);
1216 Log.d(LOG_TAG, " CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
Romain Guy484c7192011-07-25 11:56:33 -07001217 }
1218
Romain Guy786fc932012-07-24 16:24:56 -07001219 GL createEglSurface(Surface surface) throws Surface.OutOfResourcesException {
Romain Guye3924992010-06-10 18:51:21 -07001220 // Check preconditions.
Romain Guyfb8b7632010-08-23 21:05:08 -07001221 if (sEgl == null) {
Romain Guye3924992010-06-10 18:51:21 -07001222 throw new RuntimeException("egl not initialized");
Romain Guy2d614592010-06-09 18:21:37 -07001223 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001224 if (sEglDisplay == null) {
Romain Guye3924992010-06-10 18:51:21 -07001225 throw new RuntimeException("eglDisplay not initialized");
1226 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001227 if (sEglConfig == null) {
Romain Guy069ea0e2011-02-08 12:24:52 -08001228 throw new RuntimeException("eglConfig not initialized");
Romain Guye3924992010-06-10 18:51:21 -07001229 }
Romain Guy566b3ef2011-07-18 18:38:12 -07001230 if (Thread.currentThread() != mEglThread) {
Romain Guyfb8b7632010-08-23 21:05:08 -07001231 throw new IllegalStateException("HardwareRenderer cannot be used "
1232 + "from multiple threads");
1233 }
Romain Guye3924992010-06-10 18:51:21 -07001234
Romain Guy6d7475d2011-07-27 16:28:21 -07001235 // In case we need to destroy an existing surface
1236 destroySurface();
Romain Guye3924992010-06-10 18:51:21 -07001237
1238 // Create an EGL surface we can render into.
Romain Guy786fc932012-07-24 16:24:56 -07001239 if (!createSurface(surface)) {
Romain Guy1d0c7082011-08-03 16:22:24 -07001240 return null;
Romain Guye3924992010-06-10 18:51:21 -07001241 }
1242
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001243 initCaches();
Romain Guy6f7d9392011-06-02 14:17:28 -07001244
Romain Guy9477c6e2011-12-09 12:27:21 -08001245 return mEglContext.getGL();
1246 }
1247
1248 private void enableDirtyRegions() {
Romain Guy6f7d9392011-06-02 14:17:28 -07001249 // If mDirtyRegions is set, this means we have an EGL configuration
1250 // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
Romain Guy7e1160e2011-07-08 15:49:50 -07001251 if (sDirtyRegions) {
Romain Guy244ada12012-03-28 16:41:26 -07001252 if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001253 Log.w(LOG_TAG, "Backbuffer cannot be preserved");
1254 }
Romain Guy7e1160e2011-07-08 15:49:50 -07001255 } else if (sDirtyRegionsRequested) {
Romain Guy6f7d9392011-06-02 14:17:28 -07001256 // If mDirtyRegions is not set, our EGL configuration does not
1257 // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
1258 // swap behavior might be EGL_BUFFER_PRESERVED, which means we
1259 // want to set mDirtyRegions. We try to do this only if dirty
1260 // regions were initially requested as part of the device
1261 // configuration (see RENDER_DIRTY_REGIONS)
Romain Guy244ada12012-03-28 16:41:26 -07001262 mDirtyRegionsEnabled = isBackBufferPreserved();
Romain Guy7d7b5492011-01-24 16:33:45 -08001263 }
Romain Guye3924992010-06-10 18:51:21 -07001264 }
1265
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001266 abstract void initCaches();
Romain Guy3b748a42013-04-17 18:54:38 -07001267 abstract void initAtlas();
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001268
Romain Guye3924992010-06-10 18:51:21 -07001269 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
Romain Guybd431522012-09-26 13:31:25 -07001270 int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
Romain Guye3924992010-06-10 18:51:21 -07001271
Romain Guyc0029362012-09-24 20:18:13 -07001272 EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
1273 mGlVersion != 0 ? attribs : null);
Romain Guyed1b6f42012-09-24 21:42:18 -07001274 if (context == null || context == EGL_NO_CONTEXT) {
Romain Guyc0029362012-09-24 20:18:13 -07001275 //noinspection ConstantConditions
1276 throw new IllegalStateException(
1277 "Could not create an EGL context. eglCreateContext failed with error: " +
1278 GLUtils.getEGLErrorString(sEgl.eglGetError()));
1279 }
Romain Guy3b748a42013-04-17 18:54:38 -07001280
Romain Guyc0029362012-09-24 20:18:13 -07001281 return context;
Romain Guy2d614592010-06-09 18:21:37 -07001282 }
1283
1284 @Override
Romain Guy4caa4ed2010-08-25 14:46:24 -07001285 void destroy(boolean full) {
1286 if (full && mCanvas != null) {
Romain Guy4caa4ed2010-08-25 14:46:24 -07001287 mCanvas = null;
1288 }
Romain Guye3924992010-06-10 18:51:21 -07001289
Romain Guy357c9422011-08-02 11:32:49 -07001290 if (!isEnabled() || mDestroyed) {
1291 setEnabled(false);
1292 return;
1293 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001294
Romain Guy6d7475d2011-07-27 16:28:21 -07001295 destroySurface();
Romain Guye3924992010-06-10 18:51:21 -07001296 setEnabled(false);
Romain Guy357c9422011-08-02 11:32:49 -07001297
1298 mDestroyed = true;
1299 mGl = null;
Romain Guyfb8b7632010-08-23 21:05:08 -07001300 }
1301
Romain Guy6d7475d2011-07-27 16:28:21 -07001302 void destroySurface() {
1303 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
Romain Guyc8ba0b42013-06-21 16:40:30 -07001304 if (mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
1305 sEgl.eglMakeCurrent(sEglDisplay,
1306 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1307 }
Romain Guy6d7475d2011-07-27 16:28:21 -07001308 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
1309 mEglSurface = null;
1310 }
1311 }
1312
Romain Guye3924992010-06-10 18:51:21 -07001313 @Override
Romain Guy786fc932012-07-24 16:24:56 -07001314 void invalidate(Surface surface) {
Romain Guy7e1160e2011-07-08 15:49:50 -07001315 // Cancels any existing buffer to ensure we'll get a buffer
1316 // of the right size before we call eglSwapBuffers
Romain Guycf15efb2011-08-02 12:59:32 -07001317 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
Romain Guy1d0c7082011-08-03 16:22:24 -07001318
Romain Guyd3facf32011-08-03 11:14:38 -07001319 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
1320 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
Romain Guy1d0c7082011-08-03 16:22:24 -07001321 mEglSurface = null;
1322 setEnabled(false);
Romain Guyd3facf32011-08-03 11:14:38 -07001323 }
Romain Guycf15efb2011-08-02 12:59:32 -07001324
Romain Guy786fc932012-07-24 16:24:56 -07001325 if (surface.isValid()) {
1326 if (!createSurface(surface)) {
Romain Guy1d0c7082011-08-03 16:22:24 -07001327 return;
Romain Guycf15efb2011-08-02 12:59:32 -07001328 }
Romain Guy9477c6e2011-12-09 12:27:21 -08001329
1330 mUpdateDirtyRegions = true;
1331
Romain Guy86e3e222011-08-16 14:30:08 -07001332 if (mCanvas != null) {
1333 setEnabled(true);
1334 }
Romain Guycf15efb2011-08-02 12:59:32 -07001335 }
Romain Guy03985752011-07-11 15:33:51 -07001336 }
Romain Guycf15efb2011-08-02 12:59:32 -07001337
Romain Guy786fc932012-07-24 16:24:56 -07001338 private boolean createSurface(Surface surface) {
1339 mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
Romain Guy1d0c7082011-08-03 16:22:24 -07001340
1341 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
1342 int error = sEgl.eglGetError();
1343 if (error == EGL_BAD_NATIVE_WINDOW) {
1344 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
1345 return false;
1346 }
1347 throw new RuntimeException("createWindowSurface failed "
Romain Guy407ec782011-08-24 17:06:58 -07001348 + GLUtils.getEGLErrorString(error));
Romain Guy1d0c7082011-08-03 16:22:24 -07001349 }
Romain Guybd431522012-09-26 13:31:25 -07001350
1351 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
1352 throw new IllegalStateException("eglMakeCurrent failed " +
1353 GLUtils.getEGLErrorString(sEgl.eglGetError()));
1354 }
1355
1356 enableDirtyRegions();
1357
Romain Guy1d0c7082011-08-03 16:22:24 -07001358 return true;
1359 }
1360
Romain Guy03985752011-07-11 15:33:51 -07001361 @Override
1362 boolean validate() {
Romain Guycc6b7caf2013-06-24 19:19:21 -07001363 return checkRenderContext() != SURFACE_STATE_ERROR;
Romain Guy7e1160e2011-07-08 15:49:50 -07001364 }
1365
1366 @Override
Romain Guyfb8b7632010-08-23 21:05:08 -07001367 void setup(int width, int height) {
Romain Guyeca9b1f2011-08-26 13:36:37 -07001368 if (validate()) {
1369 mCanvas.setViewport(width, height);
Chet Haase40e03832011-10-06 08:34:13 -07001370 mWidth = width;
1371 mHeight = height;
Romain Guyeca9b1f2011-08-26 13:36:37 -07001372 }
Romain Guye3924992010-06-10 18:51:21 -07001373 }
Romain Guy7d7b5492011-01-24 16:33:45 -08001374
Chet Haase40e03832011-10-06 08:34:13 -07001375 @Override
1376 int getWidth() {
1377 return mWidth;
1378 }
1379
1380 @Override
1381 int getHeight() {
1382 return mHeight;
1383 }
1384
Chet Haase08837c22011-11-28 11:53:21 -08001385 @Override
1386 HardwareCanvas getCanvas() {
1387 return mCanvas;
1388 }
1389
Romain Guyef359272013-01-31 19:07:29 -08001390 @Override
1391 void setName(String name) {
1392 mName = name;
1393 }
1394
Romain Guye3924992010-06-10 18:51:21 -07001395 boolean canDraw() {
1396 return mGl != null && mCanvas != null;
1397 }
1398
Chet Haase44b2fe32012-06-06 19:03:58 -07001399 int onPreDraw(Rect dirty) {
1400 return DisplayList.STATUS_DONE;
Romain Guye3924992010-06-10 18:51:21 -07001401 }
1402
Romain Guyb025b9c2010-09-16 14:16:48 -07001403 void onPostDraw() {
1404 }
Romain Guye3924992010-06-10 18:51:21 -07001405
Romain Guy8f3b8e32012-03-27 16:33:45 -07001406 class FunctorsRunnable implements Runnable {
1407 View.AttachInfo attachInfo;
1408
1409 @Override
1410 public void run() {
1411 final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
1412 if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
1413 return;
1414 }
1415
Romain Guycc6b7caf2013-06-24 19:19:21 -07001416 if (checkRenderContext() != SURFACE_STATE_ERROR) {
Romain Guy8f3b8e32012-03-27 16:33:45 -07001417 int status = mCanvas.invokeFunctors(mRedrawClip);
1418 handleFunctorStatus(attachInfo, status);
1419 }
1420 }
1421 }
1422
Romain Guye3924992010-06-10 18:51:21 -07001423 @Override
Romain Guye55945e2013-04-04 15:26:04 -07001424 void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Romain Guy7d7b5492011-01-24 16:33:45 -08001425 Rect dirty) {
Romain Guye3924992010-06-10 18:51:21 -07001426 if (canDraw()) {
Romain Guy02ccac62011-06-24 13:20:23 -07001427 if (!hasDirtyRegions()) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001428 dirty = null;
1429 }
Romain Guye3924992010-06-10 18:51:21 -07001430 attachInfo.mIgnoreDirtyState = true;
Romain Guy02ccac62011-06-24 13:20:23 -07001431 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
1432
Dianne Hackborn4702a852012-08-17 15:18:29 -07001433 view.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy03985752011-07-11 15:33:51 -07001434
Romain Guycc6b7caf2013-06-24 19:19:21 -07001435 // We are already on the correct thread
1436 final int surfaceState = checkRenderContextUnsafe();
Romain Guyd88f54c2011-01-24 20:22:49 -08001437 if (surfaceState != SURFACE_STATE_ERROR) {
Romain Guy76878822012-03-30 14:54:22 -07001438 HardwareCanvas canvas = mCanvas;
1439 attachInfo.mHardwareCanvas = canvas;
Romain Guy77e67cf2012-06-19 16:38:50 -07001440
1441 if (mProfileEnabled) {
1442 mProfileLock.lock();
1443 }
1444
Romain Guy672433d2013-01-04 19:05:13 -08001445 dirty = beginFrame(canvas, dirty, surfaceState);
Romain Guyd88f54c2011-01-24 20:22:49 -08001446
Romain Guyd17043d2013-02-19 14:12:55 -08001447 DisplayList displayList = buildDisplayList(view, canvas);
1448
Romain Guycc6b7caf2013-06-24 19:19:21 -07001449 // buildDisplayList() calls into user code which can cause
1450 // an eglMakeCurrent to happen with a different surface/context.
1451 // We must therefore check again here.
1452 if (checkRenderContextUnsafe() == SURFACE_STATE_ERROR) {
1453 return;
1454 }
1455
Romain Guy2b7028e2012-09-19 17:25:38 -07001456 int saveCount = 0;
1457 int status = DisplayList.STATUS_DONE;
Chet Haasedaf98e92011-01-10 14:10:36 -08001458
Romain Guye9bc11f2013-05-23 12:47:26 -07001459 long start = getSystemTime();
Romain Guyb8c0de22010-12-13 14:42:34 -08001460 try {
Romain Guy672433d2013-01-04 19:05:13 -08001461 status = prepareFrame(dirty);
Jeff Brown95db2b22011-11-30 19:54:41 -08001462
Romain Guy2b7028e2012-09-19 17:25:38 -07001463 saveCount = canvas.save();
1464 callbacks.onHardwarePreDraw(canvas);
1465
Chet Haasedaf98e92011-01-10 14:10:36 -08001466 if (displayList != null) {
Chet Haase58d110a2013-04-10 07:43:29 -07001467 status |= drawDisplayList(attachInfo, canvas, displayList, status);
Chet Haasedaf98e92011-01-10 14:10:36 -08001468 } else {
1469 // Shouldn't reach here
1470 view.draw(canvas);
1471 }
Romain Guyd17043d2013-02-19 14:12:55 -08001472 } catch (Exception e) {
1473 Log.e(LOG_TAG, "An error has occurred while drawing:", e);
Romain Guyb04f7e92012-02-15 12:36:54 -08001474 } finally {
1475 callbacks.onHardwarePostDraw(canvas);
1476 canvas.restoreToCount(saveCount);
1477 view.mRecreateDisplayList = false;
Romain Guy19f86e82012-04-23 15:19:07 -07001478
Romain Guye9bc11f2013-05-23 12:47:26 -07001479 mDrawDelta = getSystemTime() - start;
Romain Guy78dd96d2013-05-03 14:24:16 -07001480
Romain Guye9bc11f2013-05-23 12:47:26 -07001481 if (mDrawDelta > 0) {
1482 mFrameCount++;
Romain Guy19f86e82012-04-23 15:19:07 -07001483
Romain Guye9bc11f2013-05-23 12:47:26 -07001484 debugOverdraw(attachInfo, dirty, canvas, displayList);
1485 debugDirtyRegions(dirty, canvas);
1486 drawProfileData(attachInfo);
1487 }
Romain Guyb8c0de22010-12-13 14:42:34 -08001488 }
Chet Haasedaf98e92011-01-10 14:10:36 -08001489
Romain Guyb8c0de22010-12-13 14:42:34 -08001490 onPostDraw();
Chet Haasedaf98e92011-01-10 14:10:36 -08001491
Romain Guy672433d2013-01-04 19:05:13 -08001492 swapBuffers(status);
Jeff Brown95db2b22011-11-30 19:54:41 -08001493
Romain Guy77e67cf2012-06-19 16:38:50 -07001494 if (mProfileEnabled) {
1495 mProfileLock.unlock();
1496 }
1497
Romain Guy672433d2013-01-04 19:05:13 -08001498 attachInfo.mIgnoreDirtyState = false;
Romain Guye3924992010-06-10 18:51:21 -07001499 }
Romain Guye3924992010-06-10 18:51:21 -07001500 }
1501 }
Romain Guy03985752011-07-11 15:33:51 -07001502
Romain Guy78dd96d2013-05-03 14:24:16 -07001503 abstract void countOverdraw(HardwareCanvas canvas);
1504 abstract float getOverdraw(HardwareCanvas canvas);
1505
1506 private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
1507 HardwareCanvas canvas, DisplayList displayList) {
1508
1509 if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
Romain Guy78dd96d2013-05-03 14:24:16 -07001510 if (mDebugOverdrawLayer == null) {
1511 mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
1512 } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
1513 mDebugOverdrawLayer.getHeight() != mHeight) {
1514 mDebugOverdrawLayer.resize(mWidth, mHeight);
1515 }
1516
1517 if (!mDebugOverdrawLayer.isValid()) {
1518 mDebugOverdraw = -1;
1519 return;
1520 }
1521
1522 HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
1523 countOverdraw(layerCanvas);
1524 final int restoreCount = layerCanvas.save();
1525 layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
1526 layerCanvas.restoreToCount(restoreCount);
1527 mDebugOverdrawLayer.end(canvas);
1528
1529 float overdraw = getOverdraw(layerCanvas);
1530 DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
1531
1532 drawOverdrawCounter(canvas, overdraw, metrics.density);
1533 }
1534 }
1535
1536 private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
1537 final String text = String.format("%.2fx", overdraw);
1538 final Paint paint = setupPaint(density);
1539 // HSBtoColor will clamp the values in the 0..1 range
1540 paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
1541
1542 canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
1543 }
1544
1545 private Paint setupPaint(float density) {
1546 if (mDebugOverdrawPaint == null) {
1547 mDebugOverdrawPaint = new Paint();
1548 mDebugOverdrawPaint.setAntiAlias(true);
1549 mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
1550 mDebugOverdrawPaint.setTextSize(density * 20.0f);
1551 }
1552 return mDebugOverdrawPaint;
1553 }
1554
Romain Guyd17043d2013-02-19 14:12:55 -08001555 private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
Romain Guye9bc11f2013-05-23 12:47:26 -07001556 if (mDrawDelta <= 0) {
1557 return view.mDisplayList;
1558 }
1559
Romain Guyd17043d2013-02-19 14:12:55 -08001560 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
1561 == View.PFLAG_INVALIDATED;
1562 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
1563
1564 long buildDisplayListStartTime = startBuildDisplayListProfiling();
1565 canvas.clearLayerUpdates();
1566
1567 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
1568 DisplayList displayList = view.getDisplayList();
1569 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1570
1571 endBuildDisplayListProfiling(buildDisplayListStartTime);
1572
1573 return displayList;
1574 }
1575
Romain Guy98e4a522013-01-07 10:58:34 -08001576 abstract void drawProfileData(View.AttachInfo attachInfo);
Romain Guy672433d2013-01-04 19:05:13 -08001577
1578 private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
1579 // We had to change the current surface and/or context, redraw everything
1580 if (surfaceState == SURFACE_STATE_UPDATED) {
1581 dirty = null;
1582 beginFrame(null);
1583 } else {
1584 int[] size = mSurfaceSize;
1585 beginFrame(size);
1586
1587 if (size[1] != mHeight || size[0] != mWidth) {
1588 mWidth = size[0];
1589 mHeight = size[1];
1590
1591 canvas.setViewport(mWidth, mHeight);
1592
1593 dirty = null;
1594 }
1595 }
1596
Romain Guy48ef4a92013-01-10 18:38:46 -08001597 if (mDebugDataProvider != null) dirty = null;
Romain Guy672433d2013-01-04 19:05:13 -08001598
1599 return dirty;
1600 }
1601
1602 private long startBuildDisplayListProfiling() {
1603 if (mProfileEnabled) {
1604 mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
1605 if (mProfileCurrentFrame >= mProfileData.length) {
1606 mProfileCurrentFrame = 0;
1607 }
1608
1609 return System.nanoTime();
1610 }
1611 return 0;
1612 }
1613
1614 private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
1615 if (mProfileEnabled) {
1616 long now = System.nanoTime();
1617 float total = (now - getDisplayListStartTime) * 0.000001f;
1618 //noinspection PointlessArithmeticExpression
1619 mProfileData[mProfileCurrentFrame] = total;
1620 }
1621 }
1622
Romain Guy672433d2013-01-04 19:05:13 -08001623 private int prepareFrame(Rect dirty) {
1624 int status;
1625 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
1626 try {
1627 status = onPreDraw(dirty);
1628 } finally {
1629 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1630 }
1631 return status;
1632 }
1633
1634 private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
1635 DisplayList displayList, int status) {
1636
1637 long drawDisplayListStartTime = 0;
1638 if (mProfileEnabled) {
1639 drawDisplayListStartTime = System.nanoTime();
1640 }
1641
1642 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
1643 try {
1644 status |= canvas.drawDisplayList(displayList, mRedrawClip,
1645 DisplayList.FLAG_CLIP_CHILDREN);
1646 } finally {
1647 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1648 }
1649
1650 if (mProfileEnabled) {
1651 long now = System.nanoTime();
1652 float total = (now - drawDisplayListStartTime) * 0.000001f;
1653 mProfileData[mProfileCurrentFrame + 1] = total;
1654 }
1655
1656 handleFunctorStatus(attachInfo, status);
1657 return status;
1658 }
1659
1660 private void swapBuffers(int status) {
1661 if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
1662 long eglSwapBuffersStartTime = 0;
1663 if (mProfileEnabled) {
1664 eglSwapBuffersStartTime = System.nanoTime();
1665 }
1666
1667 sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
1668
1669 if (mProfileEnabled) {
1670 long now = System.nanoTime();
1671 float total = (now - eglSwapBuffersStartTime) * 0.000001f;
1672 mProfileData[mProfileCurrentFrame + 2] = total;
1673 }
1674
1675 checkEglErrors();
1676 }
1677 }
1678
1679 private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
1680 if (mDebugDirtyRegions) {
1681 if (mDebugPaint == null) {
1682 mDebugPaint = new Paint();
1683 mDebugPaint.setColor(0x7fff0000);
1684 }
1685
1686 if (dirty != null && (mFrameCount & 1) == 0) {
1687 canvas.drawRect(dirty, mDebugPaint);
1688 }
1689 }
1690 }
1691
Romain Guy8f3b8e32012-03-27 16:33:45 -07001692 private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
1693 // If the draw flag is set, functors will be invoked while executing
1694 // the tree of display lists
1695 if ((status & DisplayList.STATUS_DRAW) != 0) {
1696 if (mRedrawClip.isEmpty()) {
1697 attachInfo.mViewRootImpl.invalidate();
1698 } else {
1699 attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
1700 mRedrawClip.setEmpty();
1701 }
1702 }
1703
Chris Craik9efa2222012-12-04 15:15:31 -08001704 if ((status & DisplayList.STATUS_INVOKE) != 0 ||
1705 attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
1706 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
1707 mFunctorsRunnable.attachInfo = attachInfo;
1708 attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
Romain Guy8f3b8e32012-03-27 16:33:45 -07001709 }
1710 }
1711
Romain Guyba6be8a2012-04-23 18:22:09 -07001712 @Override
1713 void detachFunctor(int functor) {
1714 if (mCanvas != null) {
1715 mCanvas.detachFunctor(functor);
Chris Craik932b7f62012-06-06 13:59:33 -07001716 }
Romain Guyba6be8a2012-04-23 18:22:09 -07001717 }
1718
1719 @Override
Chris Craik41ee4652012-05-31 15:05:57 -07001720 boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
Romain Guyba6be8a2012-04-23 18:22:09 -07001721 if (mCanvas != null) {
1722 mCanvas.attachFunctor(functor);
Chris Craik9efa2222012-12-04 15:15:31 -08001723 mFunctorsRunnable.attachInfo = attachInfo;
1724 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
1725 attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0);
Chris Craik41ee4652012-05-31 15:05:57 -07001726 return true;
Romain Guyba6be8a2012-04-23 18:22:09 -07001727 }
Chris Craik41ee4652012-05-31 15:05:57 -07001728 return false;
Romain Guyba6be8a2012-04-23 18:22:09 -07001729 }
1730
Romain Guy03985752011-07-11 15:33:51 -07001731 /**
Romain Guycc6b7caf2013-06-24 19:19:21 -07001732 * Ensures the current EGL context and surface are the ones we expect.
1733 * This method throws an IllegalStateException if invoked from a thread
1734 * that did not initialize EGL.
Romain Guy03985752011-07-11 15:33:51 -07001735 *
1736 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
1737 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
1738 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
Romain Guycc6b7caf2013-06-24 19:19:21 -07001739 *
1740 * @see #checkRenderContextUnsafe()
Romain Guy03985752011-07-11 15:33:51 -07001741 */
Romain Guycc6b7caf2013-06-24 19:19:21 -07001742 int checkRenderContext() {
Romain Guy566b3ef2011-07-18 18:38:12 -07001743 if (mEglThread != Thread.currentThread()) {
Romain Guy03985752011-07-11 15:33:51 -07001744 throw new IllegalStateException("Hardware acceleration can only be used with a " +
Romain Guy566b3ef2011-07-18 18:38:12 -07001745 "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
Romain Guy03985752011-07-11 15:33:51 -07001746 "Current thread: " + Thread.currentThread());
1747 }
1748
Romain Guycc6b7caf2013-06-24 19:19:21 -07001749 return checkRenderContextUnsafe();
1750 }
1751
1752 /**
1753 * Ensures the current EGL context and surface are the ones we expect.
1754 * This method does not check the current thread.
1755 *
1756 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
1757 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
1758 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
1759 *
1760 * @see #checkRenderContext()
1761 */
1762 private int checkRenderContextUnsafe() {
1763 if (!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) ||
1764 !mEglContext.equals(sEgl.eglGetCurrentContext())) {
Romain Guy566b3ef2011-07-18 18:38:12 -07001765 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
Romain Guy9745fae2010-12-08 11:39:15 -08001766 Log.e(LOG_TAG, "eglMakeCurrent failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001767 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guyeca9b1f2011-08-26 13:36:37 -07001768 fallback(true);
Romain Guyd88f54c2011-01-24 20:22:49 -08001769 return SURFACE_STATE_ERROR;
1770 } else {
Romain Guy9477c6e2011-12-09 12:27:21 -08001771 if (mUpdateDirtyRegions) {
1772 enableDirtyRegions();
1773 mUpdateDirtyRegions = false;
1774 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001775 return SURFACE_STATE_UPDATED;
Romain Guyfb8b7632010-08-23 21:05:08 -07001776 }
1777 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001778 return SURFACE_STATE_SUCCESS;
Romain Guyfb8b7632010-08-23 21:05:08 -07001779 }
Romain Guy48ef4a92013-01-10 18:38:46 -08001780
1781 private static int dpToPx(int dp, float density) {
1782 return (int) (dp * density + 0.5f);
1783 }
1784
1785 class DrawPerformanceDataProvider extends GraphDataProvider {
1786 private final int mGraphType;
1787
1788 private int mVerticalUnit;
1789 private int mHorizontalUnit;
1790 private int mHorizontalMargin;
1791 private int mThresholdStroke;
1792
1793 DrawPerformanceDataProvider(int graphType) {
1794 mGraphType = graphType;
1795 }
1796
1797 @Override
1798 void prepare(DisplayMetrics metrics) {
1799 final float density = metrics.density;
1800
1801 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
1802 mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
1803 mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
1804 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
1805 }
1806
1807 @Override
1808 int getGraphType() {
1809 return mGraphType;
1810 }
1811
1812 @Override
1813 int getVerticalUnitSize() {
1814 return mVerticalUnit;
1815 }
1816
1817 @Override
1818 int getHorizontalUnitSize() {
1819 return mHorizontalUnit;
1820 }
1821
1822 @Override
1823 int getHorizontaUnitMargin() {
1824 return mHorizontalMargin;
1825 }
1826
1827 @Override
1828 float[] getData() {
1829 return mProfileData;
1830 }
1831
1832 @Override
1833 float getThreshold() {
1834 return 16;
1835 }
1836
1837 @Override
1838 int getFrameCount() {
1839 return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
1840 }
1841
1842 @Override
1843 int getElementCount() {
1844 return PROFILE_FRAME_DATA_COUNT;
1845 }
1846
1847 @Override
1848 int getCurrentFrame() {
1849 return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
1850 }
1851
1852 @Override
1853 void setupGraphPaint(Paint paint, int elementIndex) {
1854 paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
1855 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
1856 }
1857
1858 @Override
1859 void setupThresholdPaint(Paint paint) {
1860 paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
1861 paint.setStrokeWidth(mThresholdStroke);
1862 }
1863
1864 @Override
1865 void setupCurrentFramePaint(Paint paint) {
1866 paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
1867 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
1868 }
1869 }
Romain Guye3924992010-06-10 18:51:21 -07001870 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001871
Romain Guye3924992010-06-10 18:51:21 -07001872 /**
1873 * Hardware renderer using OpenGL ES 2.0.
1874 */
1875 static class Gl20Renderer extends GlRenderer {
Romain Guye4d01122010-06-16 18:44:05 -07001876 private GLES20Canvas mGlCanvas;
1877
Romain Guy98e4a522013-01-07 10:58:34 -08001878 private DisplayMetrics mDisplayMetrics;
1879
Romain Guy912a7b32011-07-26 18:57:28 -07001880 private static EGLSurface sPbuffer;
1881 private static final Object[] sPbufferLock = new Object[0];
1882
Romain Guy31f2c2e2011-11-21 10:55:41 -08001883 static class Gl20RendererEglContext extends ManagedEGLContext {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001884 final Handler mHandler = new Handler();
1885
Romain Guy31f2c2e2011-11-21 10:55:41 -08001886 public Gl20RendererEglContext(EGLContext context) {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001887 super(context);
1888 }
1889
1890 @Override
1891 public void onTerminate(final EGLContext eglContext) {
1892 // Make sure we do this on the correct thread.
1893 if (mHandler.getLooper() != Looper.myLooper()) {
1894 mHandler.post(new Runnable() {
Romain Guy5d6999e2012-03-22 19:15:04 -07001895 @Override
1896 public void run() {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001897 onTerminate(eglContext);
1898 }
1899 });
1900 return;
1901 }
1902
1903 synchronized (sEglLock) {
1904 if (sEgl == null) return;
1905
1906 if (EGLImpl.getInitCount(sEglDisplay) == 1) {
1907 usePbufferSurface(eglContext);
1908 GLES20Canvas.terminateCaches();
1909
1910 sEgl.eglDestroyContext(sEglDisplay, eglContext);
Romain Guya998dff2012-03-23 18:58:36 -07001911 sEglContextStorage.set(null);
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001912 sEglContextStorage.remove();
1913
1914 sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
Romain Guy31f2c2e2011-11-21 10:55:41 -08001915 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
1916 EGL_NO_SURFACE, EGL_NO_CONTEXT);
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001917
1918 sEgl.eglReleaseThread();
1919 sEgl.eglTerminate(sEglDisplay);
1920
1921 sEgl = null;
1922 sEglDisplay = null;
1923 sEglConfig = null;
1924 sPbuffer = null;
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001925 }
1926 }
1927 }
1928 }
1929
Romain Guye4d01122010-06-16 18:44:05 -07001930 Gl20Renderer(boolean translucent) {
1931 super(2, translucent);
Romain Guye3924992010-06-10 18:51:21 -07001932 }
1933
1934 @Override
Romain Guy5d6999e2012-03-22 19:15:04 -07001935 HardwareCanvas createCanvas() {
Romain Guy6b7bd242010-10-06 19:49:23 -07001936 return mGlCanvas = new GLES20Canvas(mTranslucent);
Romain Guye4d01122010-06-16 18:44:05 -07001937 }
Romain Guye91a9c72011-05-02 14:53:30 -07001938
1939 @Override
Romain Guy5d6999e2012-03-22 19:15:04 -07001940 ManagedEGLContext createManagedContext(EGLContext eglContext) {
1941 return new Gl20Renderer.Gl20RendererEglContext(mEglContext);
1942 }
1943
1944 @Override
Romain Guye91a9c72011-05-02 14:53:30 -07001945 int[] getConfig(boolean dirtyRegions) {
Romain Guy8ce00302013-01-15 18:51:42 -08001946 //noinspection PointlessBooleanExpression,ConstantConditions
1947 final int stencilSize = GLES20Canvas.getStencilSize();
Romain Guy735738c2012-12-03 12:34:51 -08001948 final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
1949
Romain Guye91a9c72011-05-02 14:53:30 -07001950 return new int[] {
Romain Guybd431522012-09-26 13:31:25 -07001951 EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
Romain Guy484c7192011-07-25 11:56:33 -07001952 EGL_RED_SIZE, 8,
1953 EGL_GREEN_SIZE, 8,
1954 EGL_BLUE_SIZE, 8,
1955 EGL_ALPHA_SIZE, 8,
1956 EGL_DEPTH_SIZE, 0,
Romain Guy8efca542012-10-15 18:09:49 -07001957 EGL_CONFIG_CAVEAT, EGL_NONE,
Romain Guy735738c2012-12-03 12:34:51 -08001958 EGL_STENCIL_SIZE, stencilSize,
1959 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
Romain Guy484c7192011-07-25 11:56:33 -07001960 EGL_NONE
Romain Guye91a9c72011-05-02 14:53:30 -07001961 };
1962 }
Romain Guy735738c2012-12-03 12:34:51 -08001963
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001964 @Override
1965 void initCaches() {
Romain Guy3b748a42013-04-17 18:54:38 -07001966 if (GLES20Canvas.initCaches()) {
1967 // Caches were (re)initialized, rebind atlas
1968 initAtlas();
1969 }
1970 }
1971
1972 @Override
1973 void initAtlas() {
1974 IBinder binder = ServiceManager.getService("assetatlas");
Romain Guy927bc7d2013-05-03 11:32:09 -07001975 if (binder == null) return;
1976
Romain Guy3b748a42013-04-17 18:54:38 -07001977 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
1978 try {
Romain Guy80b12fc2013-05-29 15:54:25 -07001979 if (atlas.isCompatible(android.os.Process.myPpid())) {
1980 GraphicBuffer buffer = atlas.getBuffer();
1981 if (buffer != null) {
1982 int[] map = atlas.getMap();
1983 if (map != null) {
1984 GLES20Canvas.initAtlas(buffer, map);
1985 }
Romain Guyb2ed04a2013-07-09 18:56:57 -07001986 buffer.destroy();
Romain Guy3b748a42013-04-17 18:54:38 -07001987 }
1988 }
1989 } catch (RemoteException e) {
1990 Log.w(LOG_TAG, "Could not acquire atlas", e);
1991 }
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001992 }
Romain Guye91a9c72011-05-02 14:53:30 -07001993
Romain Guyb8c0de22010-12-13 14:42:34 -08001994 @Override
1995 boolean canDraw() {
1996 return super.canDraw() && mGlCanvas != null;
1997 }
Romain Guye4d01122010-06-16 18:44:05 -07001998
1999 @Override
Chet Haase44b2fe32012-06-06 19:03:58 -07002000 int onPreDraw(Rect dirty) {
2001 return mGlCanvas.onPreDraw(dirty);
Romain Guye3924992010-06-10 18:51:21 -07002002 }
2003
Romain Guyb025b9c2010-09-16 14:16:48 -07002004 @Override
2005 void onPostDraw() {
2006 mGlCanvas.onPostDraw();
2007 }
2008
Romain Guyb051e892010-09-28 19:09:36 -07002009 @Override
Romain Guy98e4a522013-01-07 10:58:34 -08002010 void drawProfileData(View.AttachInfo attachInfo) {
Romain Guy48ef4a92013-01-10 18:38:46 -08002011 if (mDebugDataProvider != null) {
2012 final GraphDataProvider provider = mDebugDataProvider;
2013 initProfileDrawData(attachInfo, provider);
Romain Guy98e4a522013-01-07 10:58:34 -08002014
Romain Guy48ef4a92013-01-10 18:38:46 -08002015 final int height = provider.getVerticalUnitSize();
2016 final int margin = provider.getHorizontaUnitMargin();
2017 final int width = provider.getHorizontalUnitSize();
Romain Guy672433d2013-01-04 19:05:13 -08002018
2019 int x = 0;
2020 int count = 0;
2021 int current = 0;
2022
Romain Guy48ef4a92013-01-10 18:38:46 -08002023 final float[] data = provider.getData();
2024 final int elementCount = provider.getElementCount();
2025 final int graphType = provider.getGraphType();
2026
2027 int totalCount = provider.getFrameCount() * elementCount;
2028 if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
2029 totalCount -= elementCount;
2030 }
2031
2032 for (int i = 0; i < totalCount; i += elementCount) {
2033 if (data[i] < 0.0f) break;
Romain Guy672433d2013-01-04 19:05:13 -08002034
2035 int index = count * 4;
Romain Guy48ef4a92013-01-10 18:38:46 -08002036 if (i == provider.getCurrentFrame() * elementCount) current = index;
Romain Guy672433d2013-01-04 19:05:13 -08002037
Romain Guy98e4a522013-01-07 10:58:34 -08002038 x += margin;
2039 int x2 = x + width;
Romain Guy672433d2013-01-04 19:05:13 -08002040
2041 int y2 = mHeight;
Romain Guy48ef4a92013-01-10 18:38:46 -08002042 int y1 = (int) (y2 - data[i] * height);
Romain Guy672433d2013-01-04 19:05:13 -08002043
Romain Guy48ef4a92013-01-10 18:38:46 -08002044 switch (graphType) {
2045 case GraphDataProvider.GRAPH_TYPE_BARS: {
2046 for (int j = 0; j < elementCount; j++) {
2047 //noinspection MismatchedReadAndWriteOfArray
2048 final float[] r = mProfileShapes[j];
2049 r[index] = x;
2050 r[index + 1] = y1;
2051 r[index + 2] = x2;
2052 r[index + 3] = y2;
Romain Guy672433d2013-01-04 19:05:13 -08002053
Romain Guy48ef4a92013-01-10 18:38:46 -08002054 y2 = y1;
2055 if (j < elementCount - 1) {
2056 y1 = (int) (y2 - data[i + j + 1] * height);
2057 }
2058 }
2059 } break;
2060 case GraphDataProvider.GRAPH_TYPE_LINES: {
2061 for (int j = 0; j < elementCount; j++) {
2062 //noinspection MismatchedReadAndWriteOfArray
2063 final float[] r = mProfileShapes[j];
2064 r[index] = (x + x2) * 0.5f;
2065 r[index + 1] = index == 0 ? y1 : r[index - 1];
2066 r[index + 2] = r[index] + width;
2067 r[index + 3] = y1;
Romain Guy672433d2013-01-04 19:05:13 -08002068
Romain Guy48ef4a92013-01-10 18:38:46 -08002069 y2 = y1;
2070 if (j < elementCount - 1) {
2071 y1 = (int) (y2 - data[i + j + 1] * height);
2072 }
2073 }
2074 } break;
2075 }
Romain Guy672433d2013-01-04 19:05:13 -08002076
Romain Guy672433d2013-01-04 19:05:13 -08002077
Romain Guy98e4a522013-01-07 10:58:34 -08002078 x += width;
Romain Guy672433d2013-01-04 19:05:13 -08002079 count++;
2080 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002081
Romain Guy98e4a522013-01-07 10:58:34 -08002082 x += margin;
Romain Guy672433d2013-01-04 19:05:13 -08002083
Romain Guy48ef4a92013-01-10 18:38:46 -08002084 drawGraph(graphType, count);
2085 drawCurrentFrame(graphType, current);
2086 drawThreshold(x, height);
Romain Guy672433d2013-01-04 19:05:13 -08002087 }
2088 }
2089
Romain Guy48ef4a92013-01-10 18:38:46 -08002090 private void drawGraph(int graphType, int count) {
2091 for (int i = 0; i < mProfileShapes.length; i++) {
2092 mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
2093 switch (graphType) {
2094 case GraphDataProvider.GRAPH_TYPE_BARS:
Chris Craik2af46352012-11-26 18:30:17 -08002095 mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
Romain Guy48ef4a92013-01-10 18:38:46 -08002096 break;
2097 case GraphDataProvider.GRAPH_TYPE_LINES:
2098 mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
2099 break;
Romain Guy672433d2013-01-04 19:05:13 -08002100 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002101 }
2102 }
2103
2104 private void drawCurrentFrame(int graphType, int index) {
2105 if (index >= 0) {
2106 mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
2107 switch (graphType) {
2108 case GraphDataProvider.GRAPH_TYPE_BARS:
2109 mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
2110 mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
2111 mProfilePaint);
2112 break;
2113 case GraphDataProvider.GRAPH_TYPE_LINES:
2114 mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
2115 mProfileShapes[2][index], mHeight, mProfilePaint);
2116 break;
2117 }
2118 }
2119 }
2120
2121 private void drawThreshold(int x, int height) {
2122 float threshold = mDebugDataProvider.getThreshold();
2123 if (threshold > 0.0f) {
2124 mDebugDataProvider.setupThresholdPaint(mProfilePaint);
2125 int y = (int) (mHeight - threshold * height);
2126 mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
2127 }
2128 }
2129
2130 private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
2131 if (mProfileShapes == null) {
2132 final int elementCount = provider.getElementCount();
2133 final int frameCount = provider.getFrameCount();
2134
2135 mProfileShapes = new float[elementCount][];
2136 for (int i = 0; i < elementCount; i++) {
2137 mProfileShapes[i] = new float[frameCount * 4];
2138 }
2139
Romain Guy672433d2013-01-04 19:05:13 -08002140 mProfilePaint = new Paint();
2141 }
Romain Guy98e4a522013-01-07 10:58:34 -08002142
Romain Guy48ef4a92013-01-10 18:38:46 -08002143 mProfilePaint.reset();
2144 if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
2145 mProfilePaint.setAntiAlias(true);
2146 }
2147
Romain Guy98e4a522013-01-07 10:58:34 -08002148 if (mDisplayMetrics == null) {
2149 mDisplayMetrics = new DisplayMetrics();
2150 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002151
Romain Guy98e4a522013-01-07 10:58:34 -08002152 attachInfo.mDisplay.getMetrics(mDisplayMetrics);
Romain Guy48ef4a92013-01-10 18:38:46 -08002153 provider.prepare(mDisplayMetrics);
Romain Guy672433d2013-01-04 19:05:13 -08002154 }
2155
2156 @Override
Romain Guy67f27952010-12-07 20:09:23 -08002157 void destroy(boolean full) {
Romain Guyb8c0de22010-12-13 14:42:34 -08002158 try {
2159 super.destroy(full);
2160 } finally {
2161 if (full && mGlCanvas != null) {
2162 mGlCanvas = null;
2163 }
Romain Guy67f27952010-12-07 20:09:23 -08002164 }
2165 }
2166
2167 @Override
Romain Guy11cb6422012-09-21 00:39:43 -07002168 void pushLayerUpdate(HardwareLayer layer) {
2169 mGlCanvas.pushLayerUpdate(layer);
2170 }
2171
2172 @Override
Romain Guye93482f2013-06-17 13:14:51 -07002173 void cancelLayerUpdate(HardwareLayer layer) {
2174 mGlCanvas.cancelLayerUpdate(layer);
2175 }
2176
2177 @Override
Romain Guy40543602013-06-12 15:31:28 -07002178 void flushLayerUpdates() {
2179 mGlCanvas.flushLayerUpdates();
2180 }
2181
2182 @Override
Romain Guy13631f32012-01-30 17:41:55 -08002183 public DisplayList createDisplayList(String name) {
2184 return new GLES20DisplayList(name);
Romain Guyb051e892010-09-28 19:09:36 -07002185 }
Romain Guyaa6c24c2011-04-28 18:40:04 -07002186
2187 @Override
Romain Guya9489272011-06-22 20:58:11 -07002188 HardwareLayer createHardwareLayer(boolean isOpaque) {
2189 return new GLES20TextureLayer(isOpaque);
Romain Guyaa6c24c2011-04-28 18:40:04 -07002190 }
2191
Romain Guy6c319ca2011-01-11 14:29:25 -08002192 @Override
Romain Guy52036b12013-02-14 18:03:37 -08002193 public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07002194 return new GLES20RenderLayer(width, height, isOpaque);
2195 }
2196
2197 @Override
Romain Guy78dd96d2013-05-03 14:24:16 -07002198 void countOverdraw(HardwareCanvas canvas) {
2199 ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
2200 }
2201
2202 @Override
2203 float getOverdraw(HardwareCanvas canvas) {
2204 return ((GLES20Canvas) canvas).getOverdraw();
2205 }
2206
2207 @Override
Romain Guy52036b12013-02-14 18:03:37 -08002208 public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07002209 return ((GLES20TextureLayer) layer).getSurfaceTexture();
2210 }
2211
Romain Guy6d7475d2011-07-27 16:28:21 -07002212 @Override
Jamie Gennis2af35242012-04-05 11:44:30 -07002213 void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
2214 ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
2215 }
2216
2217 @Override
Romain Guy1ac47652012-04-11 18:15:20 -07002218 boolean safelyRun(Runnable action) {
Romain Guycc6b7caf2013-06-24 19:19:21 -07002219 boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
Romain Guy31f2c2e2011-11-21 10:55:41 -08002220
Romain Guy1ac47652012-04-11 18:15:20 -07002221 if (needsContext) {
2222 Gl20RendererEglContext managedContext =
2223 (Gl20RendererEglContext) sEglContextStorage.get();
2224 if (managedContext == null) return false;
2225 usePbufferSurface(managedContext.getContext());
2226 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002227
Romain Guy1ac47652012-04-11 18:15:20 -07002228 try {
2229 action.run();
2230 } finally {
Jesse Hall0872b372012-04-02 12:22:51 -07002231 if (needsContext) {
2232 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
2233 EGL_NO_SURFACE, EGL_NO_CONTEXT);
2234 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002235 }
Romain Guy1ac47652012-04-11 18:15:20 -07002236
2237 return true;
2238 }
2239
2240 @Override
Romain Guybd17bd32012-10-23 19:17:15 -07002241 void destroyLayers(final View view) {
2242 if (view != null) {
2243 safelyRun(new Runnable() {
2244 @Override
2245 public void run() {
2246 if (mCanvas != null) {
2247 mCanvas.clearLayerUpdates();
2248 }
2249 destroyHardwareLayer(view);
2250 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
2251 }
2252 });
2253 }
2254 }
2255
2256 private static void destroyHardwareLayer(View view) {
2257 view.destroyLayer(true);
2258
2259 if (view instanceof ViewGroup) {
2260 ViewGroup group = (ViewGroup) view;
2261
2262 int count = group.getChildCount();
2263 for (int i = 0; i < count; i++) {
2264 destroyHardwareLayer(group.getChildAt(i));
2265 }
2266 }
2267 }
2268
2269 @Override
Romain Guy1ac47652012-04-11 18:15:20 -07002270 void destroyHardwareResources(final View view) {
2271 if (view != null) {
2272 safelyRun(new Runnable() {
2273 @Override
2274 public void run() {
Chet Haase6a2d17f2012-09-30 12:14:13 -07002275 if (mCanvas != null) {
2276 mCanvas.clearLayerUpdates();
2277 }
Romain Guy1ac47652012-04-11 18:15:20 -07002278 destroyResources(view);
2279 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
2280 }
2281 });
2282 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002283 }
Romain Guy244ada12012-03-28 16:41:26 -07002284
Romain Guy31f2c2e2011-11-21 10:55:41 -08002285 private static void destroyResources(View view) {
2286 view.destroyHardwareResources();
2287
2288 if (view instanceof ViewGroup) {
2289 ViewGroup group = (ViewGroup) view;
2290
2291 int count = group.getChildCount();
2292 for (int i = 0; i < count; i++) {
2293 destroyResources(group.getChildAt(i));
2294 }
2295 }
2296 }
Romain Guy6d7475d2011-07-27 16:28:21 -07002297
2298 static HardwareRenderer create(boolean translucent) {
2299 if (GLES20Canvas.isAvailable()) {
2300 return new Gl20Renderer(translucent);
2301 }
2302 return null;
2303 }
2304
Romain Guy19f86e82012-04-23 15:19:07 -07002305 static void startTrimMemory(int level) {
Romain Guy912a7b32011-07-26 18:57:28 -07002306 if (sEgl == null || sEglConfig == null) return;
2307
Romain Guy5d6999e2012-03-22 19:15:04 -07002308 Gl20RendererEglContext managedContext =
2309 (Gl20RendererEglContext) sEglContextStorage.get();
Romain Guy912a7b32011-07-26 18:57:28 -07002310 // We do not have OpenGL objects
Dianne Hackborn717a25d2011-11-15 18:59:59 -08002311 if (managedContext == null) {
Romain Guy912a7b32011-07-26 18:57:28 -07002312 return;
2313 } else {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08002314 usePbufferSurface(managedContext.getContext());
Romain Guye3924992010-06-10 18:51:21 -07002315 }
Romain Guy912a7b32011-07-26 18:57:28 -07002316
Dianne Hackborn27ff9132012-03-06 14:57:58 -08002317 if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
2318 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
2319 } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
2320 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
Romain Guybdf76092011-07-18 15:00:43 -07002321 }
Romain Guy19f86e82012-04-23 15:19:07 -07002322 }
Jesse Hall0872b372012-04-02 12:22:51 -07002323
Romain Guy19f86e82012-04-23 15:19:07 -07002324 static void endTrimMemory() {
2325 if (sEgl != null && sEglDisplay != null) {
2326 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
2327 }
Romain Guybdf76092011-07-18 15:00:43 -07002328 }
Romain Guy8ff6b9e2011-11-09 20:10:18 -08002329
2330 private static void usePbufferSurface(EGLContext eglContext) {
2331 synchronized (sPbufferLock) {
2332 // Create a temporary 1x1 pbuffer so we have a context
2333 // to clear our OpenGL objects
2334 if (sPbuffer == null) {
2335 sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
2336 EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
2337 });
2338 }
2339 }
2340 sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
2341 }
Romain Guye3924992010-06-10 18:51:21 -07002342 }
Romain Guy2d614592010-06-09 18:21:37 -07002343}