blob: 03428c732c2de186a1104a29c35a7576334c9e28 [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) {
1304 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1305 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
1306 mEglSurface = null;
1307 }
1308 }
1309
Romain Guye3924992010-06-10 18:51:21 -07001310 @Override
Romain Guy786fc932012-07-24 16:24:56 -07001311 void invalidate(Surface surface) {
Romain Guy7e1160e2011-07-08 15:49:50 -07001312 // Cancels any existing buffer to ensure we'll get a buffer
1313 // of the right size before we call eglSwapBuffers
Romain Guycf15efb2011-08-02 12:59:32 -07001314 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
Romain Guy1d0c7082011-08-03 16:22:24 -07001315
Romain Guyd3facf32011-08-03 11:14:38 -07001316 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
1317 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
Romain Guy1d0c7082011-08-03 16:22:24 -07001318 mEglSurface = null;
1319 setEnabled(false);
Romain Guyd3facf32011-08-03 11:14:38 -07001320 }
Romain Guycf15efb2011-08-02 12:59:32 -07001321
Romain Guy786fc932012-07-24 16:24:56 -07001322 if (surface.isValid()) {
1323 if (!createSurface(surface)) {
Romain Guy1d0c7082011-08-03 16:22:24 -07001324 return;
Romain Guycf15efb2011-08-02 12:59:32 -07001325 }
Romain Guy9477c6e2011-12-09 12:27:21 -08001326
1327 mUpdateDirtyRegions = true;
1328
Romain Guy86e3e222011-08-16 14:30:08 -07001329 if (mCanvas != null) {
1330 setEnabled(true);
1331 }
Romain Guycf15efb2011-08-02 12:59:32 -07001332 }
Romain Guy03985752011-07-11 15:33:51 -07001333 }
Romain Guycf15efb2011-08-02 12:59:32 -07001334
Romain Guy786fc932012-07-24 16:24:56 -07001335 private boolean createSurface(Surface surface) {
1336 mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
Romain Guy1d0c7082011-08-03 16:22:24 -07001337
1338 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
1339 int error = sEgl.eglGetError();
1340 if (error == EGL_BAD_NATIVE_WINDOW) {
1341 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
1342 return false;
1343 }
1344 throw new RuntimeException("createWindowSurface failed "
Romain Guy407ec782011-08-24 17:06:58 -07001345 + GLUtils.getEGLErrorString(error));
Romain Guy1d0c7082011-08-03 16:22:24 -07001346 }
Romain Guybd431522012-09-26 13:31:25 -07001347
1348 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
1349 throw new IllegalStateException("eglMakeCurrent failed " +
1350 GLUtils.getEGLErrorString(sEgl.eglGetError()));
1351 }
1352
1353 enableDirtyRegions();
1354
Romain Guy1d0c7082011-08-03 16:22:24 -07001355 return true;
1356 }
1357
Romain Guy03985752011-07-11 15:33:51 -07001358 @Override
1359 boolean validate() {
1360 return checkCurrent() != SURFACE_STATE_ERROR;
Romain Guy7e1160e2011-07-08 15:49:50 -07001361 }
1362
1363 @Override
Romain Guyfb8b7632010-08-23 21:05:08 -07001364 void setup(int width, int height) {
Romain Guyeca9b1f2011-08-26 13:36:37 -07001365 if (validate()) {
1366 mCanvas.setViewport(width, height);
Chet Haase40e03832011-10-06 08:34:13 -07001367 mWidth = width;
1368 mHeight = height;
Romain Guyeca9b1f2011-08-26 13:36:37 -07001369 }
Romain Guye3924992010-06-10 18:51:21 -07001370 }
Romain Guy7d7b5492011-01-24 16:33:45 -08001371
Chet Haase40e03832011-10-06 08:34:13 -07001372 @Override
1373 int getWidth() {
1374 return mWidth;
1375 }
1376
1377 @Override
1378 int getHeight() {
1379 return mHeight;
1380 }
1381
Chet Haase08837c22011-11-28 11:53:21 -08001382 @Override
1383 HardwareCanvas getCanvas() {
1384 return mCanvas;
1385 }
1386
Romain Guyef359272013-01-31 19:07:29 -08001387 @Override
1388 void setName(String name) {
1389 mName = name;
1390 }
1391
Romain Guye3924992010-06-10 18:51:21 -07001392 boolean canDraw() {
1393 return mGl != null && mCanvas != null;
1394 }
1395
Chet Haase44b2fe32012-06-06 19:03:58 -07001396 int onPreDraw(Rect dirty) {
1397 return DisplayList.STATUS_DONE;
Romain Guye3924992010-06-10 18:51:21 -07001398 }
1399
Romain Guyb025b9c2010-09-16 14:16:48 -07001400 void onPostDraw() {
1401 }
Romain Guye3924992010-06-10 18:51:21 -07001402
Romain Guy8f3b8e32012-03-27 16:33:45 -07001403 class FunctorsRunnable implements Runnable {
1404 View.AttachInfo attachInfo;
1405
1406 @Override
1407 public void run() {
1408 final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
1409 if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
1410 return;
1411 }
1412
1413 final int surfaceState = checkCurrent();
1414 if (surfaceState != SURFACE_STATE_ERROR) {
1415 int status = mCanvas.invokeFunctors(mRedrawClip);
1416 handleFunctorStatus(attachInfo, status);
1417 }
1418 }
1419 }
1420
Romain Guye3924992010-06-10 18:51:21 -07001421 @Override
Romain Guye55945e2013-04-04 15:26:04 -07001422 void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Romain Guy7d7b5492011-01-24 16:33:45 -08001423 Rect dirty) {
Romain Guye3924992010-06-10 18:51:21 -07001424 if (canDraw()) {
Romain Guy02ccac62011-06-24 13:20:23 -07001425 if (!hasDirtyRegions()) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001426 dirty = null;
1427 }
Romain Guye3924992010-06-10 18:51:21 -07001428 attachInfo.mIgnoreDirtyState = true;
Romain Guy02ccac62011-06-24 13:20:23 -07001429 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
1430
Dianne Hackborn4702a852012-08-17 15:18:29 -07001431 view.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy03985752011-07-11 15:33:51 -07001432
Romain Guyd88f54c2011-01-24 20:22:49 -08001433 final int surfaceState = checkCurrent();
1434 if (surfaceState != SURFACE_STATE_ERROR) {
Romain Guy76878822012-03-30 14:54:22 -07001435 HardwareCanvas canvas = mCanvas;
1436 attachInfo.mHardwareCanvas = canvas;
Romain Guy77e67cf2012-06-19 16:38:50 -07001437
1438 if (mProfileEnabled) {
1439 mProfileLock.lock();
1440 }
1441
Romain Guy672433d2013-01-04 19:05:13 -08001442 dirty = beginFrame(canvas, dirty, surfaceState);
Romain Guyd88f54c2011-01-24 20:22:49 -08001443
Romain Guyd17043d2013-02-19 14:12:55 -08001444 DisplayList displayList = buildDisplayList(view, canvas);
1445
Romain Guy2b7028e2012-09-19 17:25:38 -07001446 int saveCount = 0;
1447 int status = DisplayList.STATUS_DONE;
Chet Haasedaf98e92011-01-10 14:10:36 -08001448
Romain Guye9bc11f2013-05-23 12:47:26 -07001449 long start = getSystemTime();
Romain Guyb8c0de22010-12-13 14:42:34 -08001450 try {
Romain Guy672433d2013-01-04 19:05:13 -08001451 status = prepareFrame(dirty);
Jeff Brown95db2b22011-11-30 19:54:41 -08001452
Romain Guy2b7028e2012-09-19 17:25:38 -07001453 saveCount = canvas.save();
1454 callbacks.onHardwarePreDraw(canvas);
1455
Chet Haasedaf98e92011-01-10 14:10:36 -08001456 if (displayList != null) {
Chet Haase58d110a2013-04-10 07:43:29 -07001457 status |= drawDisplayList(attachInfo, canvas, displayList, status);
Chet Haasedaf98e92011-01-10 14:10:36 -08001458 } else {
1459 // Shouldn't reach here
1460 view.draw(canvas);
1461 }
Romain Guyd17043d2013-02-19 14:12:55 -08001462 } catch (Exception e) {
1463 Log.e(LOG_TAG, "An error has occurred while drawing:", e);
Romain Guyb04f7e92012-02-15 12:36:54 -08001464 } finally {
1465 callbacks.onHardwarePostDraw(canvas);
1466 canvas.restoreToCount(saveCount);
1467 view.mRecreateDisplayList = false;
Romain Guy19f86e82012-04-23 15:19:07 -07001468
Romain Guye9bc11f2013-05-23 12:47:26 -07001469 mDrawDelta = getSystemTime() - start;
Romain Guy78dd96d2013-05-03 14:24:16 -07001470
Romain Guye9bc11f2013-05-23 12:47:26 -07001471 if (mDrawDelta > 0) {
1472 mFrameCount++;
Romain Guy19f86e82012-04-23 15:19:07 -07001473
Romain Guye9bc11f2013-05-23 12:47:26 -07001474 debugOverdraw(attachInfo, dirty, canvas, displayList);
1475 debugDirtyRegions(dirty, canvas);
1476 drawProfileData(attachInfo);
1477 }
Romain Guyb8c0de22010-12-13 14:42:34 -08001478 }
Chet Haasedaf98e92011-01-10 14:10:36 -08001479
Romain Guyb8c0de22010-12-13 14:42:34 -08001480 onPostDraw();
Chet Haasedaf98e92011-01-10 14:10:36 -08001481
Romain Guy672433d2013-01-04 19:05:13 -08001482 swapBuffers(status);
Jeff Brown95db2b22011-11-30 19:54:41 -08001483
Romain Guy77e67cf2012-06-19 16:38:50 -07001484 if (mProfileEnabled) {
1485 mProfileLock.unlock();
1486 }
1487
Romain Guy672433d2013-01-04 19:05:13 -08001488 attachInfo.mIgnoreDirtyState = false;
Romain Guye3924992010-06-10 18:51:21 -07001489 }
Romain Guye3924992010-06-10 18:51:21 -07001490 }
1491 }
Romain Guy03985752011-07-11 15:33:51 -07001492
Romain Guy78dd96d2013-05-03 14:24:16 -07001493 abstract void countOverdraw(HardwareCanvas canvas);
1494 abstract float getOverdraw(HardwareCanvas canvas);
1495
1496 private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
1497 HardwareCanvas canvas, DisplayList displayList) {
1498
1499 if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
1500 // TODO: Use an alpha layer allocated from a GraphicBuffer
1501 // The alpha format will help with rendering performance and
1502 // the GraphicBuffer will let us skip the read pixels step
1503 if (mDebugOverdrawLayer == null) {
1504 mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
1505 } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
1506 mDebugOverdrawLayer.getHeight() != mHeight) {
1507 mDebugOverdrawLayer.resize(mWidth, mHeight);
1508 }
1509
1510 if (!mDebugOverdrawLayer.isValid()) {
1511 mDebugOverdraw = -1;
1512 return;
1513 }
1514
1515 HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
1516 countOverdraw(layerCanvas);
1517 final int restoreCount = layerCanvas.save();
1518 layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
1519 layerCanvas.restoreToCount(restoreCount);
1520 mDebugOverdrawLayer.end(canvas);
1521
1522 float overdraw = getOverdraw(layerCanvas);
1523 DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
1524
1525 drawOverdrawCounter(canvas, overdraw, metrics.density);
1526 }
1527 }
1528
1529 private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
1530 final String text = String.format("%.2fx", overdraw);
1531 final Paint paint = setupPaint(density);
1532 // HSBtoColor will clamp the values in the 0..1 range
1533 paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
1534
1535 canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
1536 }
1537
1538 private Paint setupPaint(float density) {
1539 if (mDebugOverdrawPaint == null) {
1540 mDebugOverdrawPaint = new Paint();
1541 mDebugOverdrawPaint.setAntiAlias(true);
1542 mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
1543 mDebugOverdrawPaint.setTextSize(density * 20.0f);
1544 }
1545 return mDebugOverdrawPaint;
1546 }
1547
Romain Guyd17043d2013-02-19 14:12:55 -08001548 private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
Romain Guye9bc11f2013-05-23 12:47:26 -07001549 if (mDrawDelta <= 0) {
1550 return view.mDisplayList;
1551 }
1552
Romain Guyd17043d2013-02-19 14:12:55 -08001553 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
1554 == View.PFLAG_INVALIDATED;
1555 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
1556
1557 long buildDisplayListStartTime = startBuildDisplayListProfiling();
1558 canvas.clearLayerUpdates();
1559
1560 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
1561 DisplayList displayList = view.getDisplayList();
1562 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1563
1564 endBuildDisplayListProfiling(buildDisplayListStartTime);
1565
1566 return displayList;
1567 }
1568
Romain Guy98e4a522013-01-07 10:58:34 -08001569 abstract void drawProfileData(View.AttachInfo attachInfo);
Romain Guy672433d2013-01-04 19:05:13 -08001570
1571 private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
1572 // We had to change the current surface and/or context, redraw everything
1573 if (surfaceState == SURFACE_STATE_UPDATED) {
1574 dirty = null;
1575 beginFrame(null);
1576 } else {
1577 int[] size = mSurfaceSize;
1578 beginFrame(size);
1579
1580 if (size[1] != mHeight || size[0] != mWidth) {
1581 mWidth = size[0];
1582 mHeight = size[1];
1583
1584 canvas.setViewport(mWidth, mHeight);
1585
1586 dirty = null;
1587 }
1588 }
1589
Romain Guy48ef4a92013-01-10 18:38:46 -08001590 if (mDebugDataProvider != null) dirty = null;
Romain Guy672433d2013-01-04 19:05:13 -08001591
1592 return dirty;
1593 }
1594
1595 private long startBuildDisplayListProfiling() {
1596 if (mProfileEnabled) {
1597 mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
1598 if (mProfileCurrentFrame >= mProfileData.length) {
1599 mProfileCurrentFrame = 0;
1600 }
1601
1602 return System.nanoTime();
1603 }
1604 return 0;
1605 }
1606
1607 private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
1608 if (mProfileEnabled) {
1609 long now = System.nanoTime();
1610 float total = (now - getDisplayListStartTime) * 0.000001f;
1611 //noinspection PointlessArithmeticExpression
1612 mProfileData[mProfileCurrentFrame] = total;
1613 }
1614 }
1615
Romain Guy672433d2013-01-04 19:05:13 -08001616 private int prepareFrame(Rect dirty) {
1617 int status;
1618 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
1619 try {
1620 status = onPreDraw(dirty);
1621 } finally {
1622 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1623 }
1624 return status;
1625 }
1626
1627 private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
1628 DisplayList displayList, int status) {
1629
1630 long drawDisplayListStartTime = 0;
1631 if (mProfileEnabled) {
1632 drawDisplayListStartTime = System.nanoTime();
1633 }
1634
1635 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
1636 try {
1637 status |= canvas.drawDisplayList(displayList, mRedrawClip,
1638 DisplayList.FLAG_CLIP_CHILDREN);
1639 } finally {
1640 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1641 }
1642
1643 if (mProfileEnabled) {
1644 long now = System.nanoTime();
1645 float total = (now - drawDisplayListStartTime) * 0.000001f;
1646 mProfileData[mProfileCurrentFrame + 1] = total;
1647 }
1648
1649 handleFunctorStatus(attachInfo, status);
1650 return status;
1651 }
1652
1653 private void swapBuffers(int status) {
1654 if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
1655 long eglSwapBuffersStartTime = 0;
1656 if (mProfileEnabled) {
1657 eglSwapBuffersStartTime = System.nanoTime();
1658 }
1659
1660 sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
1661
1662 if (mProfileEnabled) {
1663 long now = System.nanoTime();
1664 float total = (now - eglSwapBuffersStartTime) * 0.000001f;
1665 mProfileData[mProfileCurrentFrame + 2] = total;
1666 }
1667
1668 checkEglErrors();
1669 }
1670 }
1671
1672 private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
1673 if (mDebugDirtyRegions) {
1674 if (mDebugPaint == null) {
1675 mDebugPaint = new Paint();
1676 mDebugPaint.setColor(0x7fff0000);
1677 }
1678
1679 if (dirty != null && (mFrameCount & 1) == 0) {
1680 canvas.drawRect(dirty, mDebugPaint);
1681 }
1682 }
1683 }
1684
Romain Guy8f3b8e32012-03-27 16:33:45 -07001685 private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
1686 // If the draw flag is set, functors will be invoked while executing
1687 // the tree of display lists
1688 if ((status & DisplayList.STATUS_DRAW) != 0) {
1689 if (mRedrawClip.isEmpty()) {
1690 attachInfo.mViewRootImpl.invalidate();
1691 } else {
1692 attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
1693 mRedrawClip.setEmpty();
1694 }
1695 }
1696
Chris Craik9efa2222012-12-04 15:15:31 -08001697 if ((status & DisplayList.STATUS_INVOKE) != 0 ||
1698 attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
1699 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
1700 mFunctorsRunnable.attachInfo = attachInfo;
1701 attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
Romain Guy8f3b8e32012-03-27 16:33:45 -07001702 }
1703 }
1704
Romain Guyba6be8a2012-04-23 18:22:09 -07001705 @Override
1706 void detachFunctor(int functor) {
1707 if (mCanvas != null) {
1708 mCanvas.detachFunctor(functor);
Chris Craik932b7f62012-06-06 13:59:33 -07001709 }
Romain Guyba6be8a2012-04-23 18:22:09 -07001710 }
1711
1712 @Override
Chris Craik41ee4652012-05-31 15:05:57 -07001713 boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
Romain Guyba6be8a2012-04-23 18:22:09 -07001714 if (mCanvas != null) {
1715 mCanvas.attachFunctor(functor);
Chris Craik9efa2222012-12-04 15:15:31 -08001716 mFunctorsRunnable.attachInfo = attachInfo;
1717 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
1718 attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0);
Chris Craik41ee4652012-05-31 15:05:57 -07001719 return true;
Romain Guyba6be8a2012-04-23 18:22:09 -07001720 }
Chris Craik41ee4652012-05-31 15:05:57 -07001721 return false;
Romain Guyba6be8a2012-04-23 18:22:09 -07001722 }
1723
Romain Guy03985752011-07-11 15:33:51 -07001724 /**
Romain Guy566b3ef2011-07-18 18:38:12 -07001725 * Ensures the current EGL context is the one we expect.
Romain Guy03985752011-07-11 15:33:51 -07001726 *
1727 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
1728 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
1729 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
1730 */
Romain Guy912a7b32011-07-26 18:57:28 -07001731 int checkCurrent() {
Romain Guy566b3ef2011-07-18 18:38:12 -07001732 if (mEglThread != Thread.currentThread()) {
Romain Guy03985752011-07-11 15:33:51 -07001733 throw new IllegalStateException("Hardware acceleration can only be used with a " +
Romain Guy566b3ef2011-07-18 18:38:12 -07001734 "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
Romain Guy03985752011-07-11 15:33:51 -07001735 "Current thread: " + Thread.currentThread());
1736 }
1737
Romain Guy566b3ef2011-07-18 18:38:12 -07001738 if (!mEglContext.equals(sEgl.eglGetCurrentContext()) ||
Romain Guy484c7192011-07-25 11:56:33 -07001739 !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
Romain Guy566b3ef2011-07-18 18:38:12 -07001740 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
Romain Guy9745fae2010-12-08 11:39:15 -08001741 Log.e(LOG_TAG, "eglMakeCurrent failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001742 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guyeca9b1f2011-08-26 13:36:37 -07001743 fallback(true);
Romain Guyd88f54c2011-01-24 20:22:49 -08001744 return SURFACE_STATE_ERROR;
1745 } else {
Romain Guy9477c6e2011-12-09 12:27:21 -08001746 if (mUpdateDirtyRegions) {
1747 enableDirtyRegions();
1748 mUpdateDirtyRegions = false;
1749 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001750 return SURFACE_STATE_UPDATED;
Romain Guyfb8b7632010-08-23 21:05:08 -07001751 }
1752 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001753 return SURFACE_STATE_SUCCESS;
Romain Guyfb8b7632010-08-23 21:05:08 -07001754 }
Romain Guy48ef4a92013-01-10 18:38:46 -08001755
1756 private static int dpToPx(int dp, float density) {
1757 return (int) (dp * density + 0.5f);
1758 }
1759
1760 class DrawPerformanceDataProvider extends GraphDataProvider {
1761 private final int mGraphType;
1762
1763 private int mVerticalUnit;
1764 private int mHorizontalUnit;
1765 private int mHorizontalMargin;
1766 private int mThresholdStroke;
1767
1768 DrawPerformanceDataProvider(int graphType) {
1769 mGraphType = graphType;
1770 }
1771
1772 @Override
1773 void prepare(DisplayMetrics metrics) {
1774 final float density = metrics.density;
1775
1776 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
1777 mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
1778 mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
1779 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
1780 }
1781
1782 @Override
1783 int getGraphType() {
1784 return mGraphType;
1785 }
1786
1787 @Override
1788 int getVerticalUnitSize() {
1789 return mVerticalUnit;
1790 }
1791
1792 @Override
1793 int getHorizontalUnitSize() {
1794 return mHorizontalUnit;
1795 }
1796
1797 @Override
1798 int getHorizontaUnitMargin() {
1799 return mHorizontalMargin;
1800 }
1801
1802 @Override
1803 float[] getData() {
1804 return mProfileData;
1805 }
1806
1807 @Override
1808 float getThreshold() {
1809 return 16;
1810 }
1811
1812 @Override
1813 int getFrameCount() {
1814 return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
1815 }
1816
1817 @Override
1818 int getElementCount() {
1819 return PROFILE_FRAME_DATA_COUNT;
1820 }
1821
1822 @Override
1823 int getCurrentFrame() {
1824 return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
1825 }
1826
1827 @Override
1828 void setupGraphPaint(Paint paint, int elementIndex) {
1829 paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
1830 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
1831 }
1832
1833 @Override
1834 void setupThresholdPaint(Paint paint) {
1835 paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
1836 paint.setStrokeWidth(mThresholdStroke);
1837 }
1838
1839 @Override
1840 void setupCurrentFramePaint(Paint paint) {
1841 paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
1842 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
1843 }
1844 }
Romain Guye3924992010-06-10 18:51:21 -07001845 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001846
Romain Guye3924992010-06-10 18:51:21 -07001847 /**
1848 * Hardware renderer using OpenGL ES 2.0.
1849 */
1850 static class Gl20Renderer extends GlRenderer {
Romain Guye4d01122010-06-16 18:44:05 -07001851 private GLES20Canvas mGlCanvas;
1852
Romain Guy98e4a522013-01-07 10:58:34 -08001853 private DisplayMetrics mDisplayMetrics;
1854
Romain Guy912a7b32011-07-26 18:57:28 -07001855 private static EGLSurface sPbuffer;
1856 private static final Object[] sPbufferLock = new Object[0];
1857
Romain Guy31f2c2e2011-11-21 10:55:41 -08001858 static class Gl20RendererEglContext extends ManagedEGLContext {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001859 final Handler mHandler = new Handler();
1860
Romain Guy31f2c2e2011-11-21 10:55:41 -08001861 public Gl20RendererEglContext(EGLContext context) {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001862 super(context);
1863 }
1864
1865 @Override
1866 public void onTerminate(final EGLContext eglContext) {
1867 // Make sure we do this on the correct thread.
1868 if (mHandler.getLooper() != Looper.myLooper()) {
1869 mHandler.post(new Runnable() {
Romain Guy5d6999e2012-03-22 19:15:04 -07001870 @Override
1871 public void run() {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001872 onTerminate(eglContext);
1873 }
1874 });
1875 return;
1876 }
1877
1878 synchronized (sEglLock) {
1879 if (sEgl == null) return;
1880
1881 if (EGLImpl.getInitCount(sEglDisplay) == 1) {
1882 usePbufferSurface(eglContext);
1883 GLES20Canvas.terminateCaches();
1884
1885 sEgl.eglDestroyContext(sEglDisplay, eglContext);
Romain Guya998dff2012-03-23 18:58:36 -07001886 sEglContextStorage.set(null);
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001887 sEglContextStorage.remove();
1888
1889 sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
Romain Guy31f2c2e2011-11-21 10:55:41 -08001890 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
1891 EGL_NO_SURFACE, EGL_NO_CONTEXT);
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001892
1893 sEgl.eglReleaseThread();
1894 sEgl.eglTerminate(sEglDisplay);
1895
1896 sEgl = null;
1897 sEglDisplay = null;
1898 sEglConfig = null;
1899 sPbuffer = null;
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001900 }
1901 }
1902 }
1903 }
1904
Romain Guye4d01122010-06-16 18:44:05 -07001905 Gl20Renderer(boolean translucent) {
1906 super(2, translucent);
Romain Guye3924992010-06-10 18:51:21 -07001907 }
1908
1909 @Override
Romain Guy5d6999e2012-03-22 19:15:04 -07001910 HardwareCanvas createCanvas() {
Romain Guy6b7bd242010-10-06 19:49:23 -07001911 return mGlCanvas = new GLES20Canvas(mTranslucent);
Romain Guye4d01122010-06-16 18:44:05 -07001912 }
Romain Guye91a9c72011-05-02 14:53:30 -07001913
1914 @Override
Romain Guy5d6999e2012-03-22 19:15:04 -07001915 ManagedEGLContext createManagedContext(EGLContext eglContext) {
1916 return new Gl20Renderer.Gl20RendererEglContext(mEglContext);
1917 }
1918
1919 @Override
Romain Guye91a9c72011-05-02 14:53:30 -07001920 int[] getConfig(boolean dirtyRegions) {
Romain Guy8ce00302013-01-15 18:51:42 -08001921 //noinspection PointlessBooleanExpression,ConstantConditions
1922 final int stencilSize = GLES20Canvas.getStencilSize();
Romain Guy735738c2012-12-03 12:34:51 -08001923 final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
1924
Romain Guye91a9c72011-05-02 14:53:30 -07001925 return new int[] {
Romain Guybd431522012-09-26 13:31:25 -07001926 EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
Romain Guy484c7192011-07-25 11:56:33 -07001927 EGL_RED_SIZE, 8,
1928 EGL_GREEN_SIZE, 8,
1929 EGL_BLUE_SIZE, 8,
1930 EGL_ALPHA_SIZE, 8,
1931 EGL_DEPTH_SIZE, 0,
Romain Guy8efca542012-10-15 18:09:49 -07001932 EGL_CONFIG_CAVEAT, EGL_NONE,
Romain Guy735738c2012-12-03 12:34:51 -08001933 EGL_STENCIL_SIZE, stencilSize,
1934 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
Romain Guy484c7192011-07-25 11:56:33 -07001935 EGL_NONE
Romain Guye91a9c72011-05-02 14:53:30 -07001936 };
1937 }
Romain Guy735738c2012-12-03 12:34:51 -08001938
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001939 @Override
1940 void initCaches() {
Romain Guy3b748a42013-04-17 18:54:38 -07001941 if (GLES20Canvas.initCaches()) {
1942 // Caches were (re)initialized, rebind atlas
1943 initAtlas();
1944 }
1945 }
1946
1947 @Override
1948 void initAtlas() {
1949 IBinder binder = ServiceManager.getService("assetatlas");
Romain Guy927bc7d2013-05-03 11:32:09 -07001950 if (binder == null) return;
1951
Romain Guy3b748a42013-04-17 18:54:38 -07001952 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
1953 try {
Romain Guy80b12fc2013-05-29 15:54:25 -07001954 if (atlas.isCompatible(android.os.Process.myPpid())) {
1955 GraphicBuffer buffer = atlas.getBuffer();
1956 if (buffer != null) {
1957 int[] map = atlas.getMap();
1958 if (map != null) {
1959 GLES20Canvas.initAtlas(buffer, map);
1960 }
Romain Guy3b748a42013-04-17 18:54:38 -07001961 }
1962 }
1963 } catch (RemoteException e) {
1964 Log.w(LOG_TAG, "Could not acquire atlas", e);
1965 }
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001966 }
Romain Guye91a9c72011-05-02 14:53:30 -07001967
Romain Guyb8c0de22010-12-13 14:42:34 -08001968 @Override
1969 boolean canDraw() {
1970 return super.canDraw() && mGlCanvas != null;
1971 }
Romain Guye4d01122010-06-16 18:44:05 -07001972
1973 @Override
Chet Haase44b2fe32012-06-06 19:03:58 -07001974 int onPreDraw(Rect dirty) {
1975 return mGlCanvas.onPreDraw(dirty);
Romain Guye3924992010-06-10 18:51:21 -07001976 }
1977
Romain Guyb025b9c2010-09-16 14:16:48 -07001978 @Override
1979 void onPostDraw() {
1980 mGlCanvas.onPostDraw();
1981 }
1982
Romain Guyb051e892010-09-28 19:09:36 -07001983 @Override
Romain Guy98e4a522013-01-07 10:58:34 -08001984 void drawProfileData(View.AttachInfo attachInfo) {
Romain Guy48ef4a92013-01-10 18:38:46 -08001985 if (mDebugDataProvider != null) {
1986 final GraphDataProvider provider = mDebugDataProvider;
1987 initProfileDrawData(attachInfo, provider);
Romain Guy98e4a522013-01-07 10:58:34 -08001988
Romain Guy48ef4a92013-01-10 18:38:46 -08001989 final int height = provider.getVerticalUnitSize();
1990 final int margin = provider.getHorizontaUnitMargin();
1991 final int width = provider.getHorizontalUnitSize();
Romain Guy672433d2013-01-04 19:05:13 -08001992
1993 int x = 0;
1994 int count = 0;
1995 int current = 0;
1996
Romain Guy48ef4a92013-01-10 18:38:46 -08001997 final float[] data = provider.getData();
1998 final int elementCount = provider.getElementCount();
1999 final int graphType = provider.getGraphType();
2000
2001 int totalCount = provider.getFrameCount() * elementCount;
2002 if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
2003 totalCount -= elementCount;
2004 }
2005
2006 for (int i = 0; i < totalCount; i += elementCount) {
2007 if (data[i] < 0.0f) break;
Romain Guy672433d2013-01-04 19:05:13 -08002008
2009 int index = count * 4;
Romain Guy48ef4a92013-01-10 18:38:46 -08002010 if (i == provider.getCurrentFrame() * elementCount) current = index;
Romain Guy672433d2013-01-04 19:05:13 -08002011
Romain Guy98e4a522013-01-07 10:58:34 -08002012 x += margin;
2013 int x2 = x + width;
Romain Guy672433d2013-01-04 19:05:13 -08002014
2015 int y2 = mHeight;
Romain Guy48ef4a92013-01-10 18:38:46 -08002016 int y1 = (int) (y2 - data[i] * height);
Romain Guy672433d2013-01-04 19:05:13 -08002017
Romain Guy48ef4a92013-01-10 18:38:46 -08002018 switch (graphType) {
2019 case GraphDataProvider.GRAPH_TYPE_BARS: {
2020 for (int j = 0; j < elementCount; j++) {
2021 //noinspection MismatchedReadAndWriteOfArray
2022 final float[] r = mProfileShapes[j];
2023 r[index] = x;
2024 r[index + 1] = y1;
2025 r[index + 2] = x2;
2026 r[index + 3] = y2;
Romain Guy672433d2013-01-04 19:05:13 -08002027
Romain Guy48ef4a92013-01-10 18:38:46 -08002028 y2 = y1;
2029 if (j < elementCount - 1) {
2030 y1 = (int) (y2 - data[i + j + 1] * height);
2031 }
2032 }
2033 } break;
2034 case GraphDataProvider.GRAPH_TYPE_LINES: {
2035 for (int j = 0; j < elementCount; j++) {
2036 //noinspection MismatchedReadAndWriteOfArray
2037 final float[] r = mProfileShapes[j];
2038 r[index] = (x + x2) * 0.5f;
2039 r[index + 1] = index == 0 ? y1 : r[index - 1];
2040 r[index + 2] = r[index] + width;
2041 r[index + 3] = y1;
Romain Guy672433d2013-01-04 19:05:13 -08002042
Romain Guy48ef4a92013-01-10 18:38:46 -08002043 y2 = y1;
2044 if (j < elementCount - 1) {
2045 y1 = (int) (y2 - data[i + j + 1] * height);
2046 }
2047 }
2048 } break;
2049 }
Romain Guy672433d2013-01-04 19:05:13 -08002050
Romain Guy672433d2013-01-04 19:05:13 -08002051
Romain Guy98e4a522013-01-07 10:58:34 -08002052 x += width;
Romain Guy672433d2013-01-04 19:05:13 -08002053 count++;
2054 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002055
Romain Guy98e4a522013-01-07 10:58:34 -08002056 x += margin;
Romain Guy672433d2013-01-04 19:05:13 -08002057
Romain Guy48ef4a92013-01-10 18:38:46 -08002058 drawGraph(graphType, count);
2059 drawCurrentFrame(graphType, current);
2060 drawThreshold(x, height);
Romain Guy672433d2013-01-04 19:05:13 -08002061 }
2062 }
2063
Romain Guy48ef4a92013-01-10 18:38:46 -08002064 private void drawGraph(int graphType, int count) {
2065 for (int i = 0; i < mProfileShapes.length; i++) {
2066 mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
2067 switch (graphType) {
2068 case GraphDataProvider.GRAPH_TYPE_BARS:
Chris Craik2af46352012-11-26 18:30:17 -08002069 mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
Romain Guy48ef4a92013-01-10 18:38:46 -08002070 break;
2071 case GraphDataProvider.GRAPH_TYPE_LINES:
2072 mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
2073 break;
Romain Guy672433d2013-01-04 19:05:13 -08002074 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002075 }
2076 }
2077
2078 private void drawCurrentFrame(int graphType, int index) {
2079 if (index >= 0) {
2080 mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
2081 switch (graphType) {
2082 case GraphDataProvider.GRAPH_TYPE_BARS:
2083 mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
2084 mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
2085 mProfilePaint);
2086 break;
2087 case GraphDataProvider.GRAPH_TYPE_LINES:
2088 mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
2089 mProfileShapes[2][index], mHeight, mProfilePaint);
2090 break;
2091 }
2092 }
2093 }
2094
2095 private void drawThreshold(int x, int height) {
2096 float threshold = mDebugDataProvider.getThreshold();
2097 if (threshold > 0.0f) {
2098 mDebugDataProvider.setupThresholdPaint(mProfilePaint);
2099 int y = (int) (mHeight - threshold * height);
2100 mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
2101 }
2102 }
2103
2104 private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
2105 if (mProfileShapes == null) {
2106 final int elementCount = provider.getElementCount();
2107 final int frameCount = provider.getFrameCount();
2108
2109 mProfileShapes = new float[elementCount][];
2110 for (int i = 0; i < elementCount; i++) {
2111 mProfileShapes[i] = new float[frameCount * 4];
2112 }
2113
Romain Guy672433d2013-01-04 19:05:13 -08002114 mProfilePaint = new Paint();
2115 }
Romain Guy98e4a522013-01-07 10:58:34 -08002116
Romain Guy48ef4a92013-01-10 18:38:46 -08002117 mProfilePaint.reset();
2118 if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
2119 mProfilePaint.setAntiAlias(true);
2120 }
2121
Romain Guy98e4a522013-01-07 10:58:34 -08002122 if (mDisplayMetrics == null) {
2123 mDisplayMetrics = new DisplayMetrics();
2124 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002125
Romain Guy98e4a522013-01-07 10:58:34 -08002126 attachInfo.mDisplay.getMetrics(mDisplayMetrics);
Romain Guy48ef4a92013-01-10 18:38:46 -08002127 provider.prepare(mDisplayMetrics);
Romain Guy672433d2013-01-04 19:05:13 -08002128 }
2129
2130 @Override
Romain Guy67f27952010-12-07 20:09:23 -08002131 void destroy(boolean full) {
Romain Guyb8c0de22010-12-13 14:42:34 -08002132 try {
2133 super.destroy(full);
2134 } finally {
2135 if (full && mGlCanvas != null) {
2136 mGlCanvas = null;
2137 }
Romain Guy67f27952010-12-07 20:09:23 -08002138 }
2139 }
2140
2141 @Override
Romain Guy11cb6422012-09-21 00:39:43 -07002142 void pushLayerUpdate(HardwareLayer layer) {
2143 mGlCanvas.pushLayerUpdate(layer);
2144 }
2145
2146 @Override
Romain Guye93482f2013-06-17 13:14:51 -07002147 void cancelLayerUpdate(HardwareLayer layer) {
2148 mGlCanvas.cancelLayerUpdate(layer);
2149 }
2150
2151 @Override
Romain Guy40543602013-06-12 15:31:28 -07002152 void flushLayerUpdates() {
2153 mGlCanvas.flushLayerUpdates();
2154 }
2155
2156 @Override
Romain Guy13631f32012-01-30 17:41:55 -08002157 public DisplayList createDisplayList(String name) {
2158 return new GLES20DisplayList(name);
Romain Guyb051e892010-09-28 19:09:36 -07002159 }
Romain Guyaa6c24c2011-04-28 18:40:04 -07002160
2161 @Override
Romain Guya9489272011-06-22 20:58:11 -07002162 HardwareLayer createHardwareLayer(boolean isOpaque) {
2163 return new GLES20TextureLayer(isOpaque);
Romain Guyaa6c24c2011-04-28 18:40:04 -07002164 }
2165
Romain Guy6c319ca2011-01-11 14:29:25 -08002166 @Override
Romain Guy52036b12013-02-14 18:03:37 -08002167 public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07002168 return new GLES20RenderLayer(width, height, isOpaque);
2169 }
2170
2171 @Override
Romain Guy78dd96d2013-05-03 14:24:16 -07002172 void countOverdraw(HardwareCanvas canvas) {
2173 ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
2174 }
2175
2176 @Override
2177 float getOverdraw(HardwareCanvas canvas) {
2178 return ((GLES20Canvas) canvas).getOverdraw();
2179 }
2180
2181 @Override
Romain Guy52036b12013-02-14 18:03:37 -08002182 public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07002183 return ((GLES20TextureLayer) layer).getSurfaceTexture();
2184 }
2185
Romain Guy6d7475d2011-07-27 16:28:21 -07002186 @Override
Jamie Gennis2af35242012-04-05 11:44:30 -07002187 void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
2188 ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
2189 }
2190
2191 @Override
Romain Guy1ac47652012-04-11 18:15:20 -07002192 boolean safelyRun(Runnable action) {
2193 boolean needsContext = true;
2194 if (isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) needsContext = false;
Romain Guy31f2c2e2011-11-21 10:55:41 -08002195
Romain Guy1ac47652012-04-11 18:15:20 -07002196 if (needsContext) {
2197 Gl20RendererEglContext managedContext =
2198 (Gl20RendererEglContext) sEglContextStorage.get();
2199 if (managedContext == null) return false;
2200 usePbufferSurface(managedContext.getContext());
2201 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002202
Romain Guy1ac47652012-04-11 18:15:20 -07002203 try {
2204 action.run();
2205 } finally {
Jesse Hall0872b372012-04-02 12:22:51 -07002206 if (needsContext) {
2207 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
2208 EGL_NO_SURFACE, EGL_NO_CONTEXT);
2209 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002210 }
Romain Guy1ac47652012-04-11 18:15:20 -07002211
2212 return true;
2213 }
2214
2215 @Override
Romain Guybd17bd32012-10-23 19:17:15 -07002216 void destroyLayers(final View view) {
2217 if (view != null) {
2218 safelyRun(new Runnable() {
2219 @Override
2220 public void run() {
2221 if (mCanvas != null) {
2222 mCanvas.clearLayerUpdates();
2223 }
2224 destroyHardwareLayer(view);
2225 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
2226 }
2227 });
2228 }
2229 }
2230
2231 private static void destroyHardwareLayer(View view) {
2232 view.destroyLayer(true);
2233
2234 if (view instanceof ViewGroup) {
2235 ViewGroup group = (ViewGroup) view;
2236
2237 int count = group.getChildCount();
2238 for (int i = 0; i < count; i++) {
2239 destroyHardwareLayer(group.getChildAt(i));
2240 }
2241 }
2242 }
2243
2244 @Override
Romain Guy1ac47652012-04-11 18:15:20 -07002245 void destroyHardwareResources(final View view) {
2246 if (view != null) {
2247 safelyRun(new Runnable() {
2248 @Override
2249 public void run() {
Chet Haase6a2d17f2012-09-30 12:14:13 -07002250 if (mCanvas != null) {
2251 mCanvas.clearLayerUpdates();
2252 }
Romain Guy1ac47652012-04-11 18:15:20 -07002253 destroyResources(view);
2254 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
2255 }
2256 });
2257 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002258 }
Romain Guy244ada12012-03-28 16:41:26 -07002259
Romain Guy31f2c2e2011-11-21 10:55:41 -08002260 private static void destroyResources(View view) {
2261 view.destroyHardwareResources();
2262
2263 if (view instanceof ViewGroup) {
2264 ViewGroup group = (ViewGroup) view;
2265
2266 int count = group.getChildCount();
2267 for (int i = 0; i < count; i++) {
2268 destroyResources(group.getChildAt(i));
2269 }
2270 }
2271 }
Romain Guy6d7475d2011-07-27 16:28:21 -07002272
2273 static HardwareRenderer create(boolean translucent) {
2274 if (GLES20Canvas.isAvailable()) {
2275 return new Gl20Renderer(translucent);
2276 }
2277 return null;
2278 }
2279
Romain Guy19f86e82012-04-23 15:19:07 -07002280 static void startTrimMemory(int level) {
Romain Guy912a7b32011-07-26 18:57:28 -07002281 if (sEgl == null || sEglConfig == null) return;
2282
Romain Guy5d6999e2012-03-22 19:15:04 -07002283 Gl20RendererEglContext managedContext =
2284 (Gl20RendererEglContext) sEglContextStorage.get();
Romain Guy912a7b32011-07-26 18:57:28 -07002285 // We do not have OpenGL objects
Dianne Hackborn717a25d2011-11-15 18:59:59 -08002286 if (managedContext == null) {
Romain Guy912a7b32011-07-26 18:57:28 -07002287 return;
2288 } else {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08002289 usePbufferSurface(managedContext.getContext());
Romain Guye3924992010-06-10 18:51:21 -07002290 }
Romain Guy912a7b32011-07-26 18:57:28 -07002291
Dianne Hackborn27ff9132012-03-06 14:57:58 -08002292 if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
2293 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
2294 } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
2295 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
Romain Guybdf76092011-07-18 15:00:43 -07002296 }
Romain Guy19f86e82012-04-23 15:19:07 -07002297 }
Jesse Hall0872b372012-04-02 12:22:51 -07002298
Romain Guy19f86e82012-04-23 15:19:07 -07002299 static void endTrimMemory() {
2300 if (sEgl != null && sEglDisplay != null) {
2301 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
2302 }
Romain Guybdf76092011-07-18 15:00:43 -07002303 }
Romain Guy8ff6b9e2011-11-09 20:10:18 -08002304
2305 private static void usePbufferSurface(EGLContext eglContext) {
2306 synchronized (sPbufferLock) {
2307 // Create a temporary 1x1 pbuffer so we have a context
2308 // to clear our OpenGL objects
2309 if (sPbuffer == null) {
2310 sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
2311 EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
2312 });
2313 }
2314 }
2315 sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
2316 }
Romain Guye3924992010-06-10 18:51:21 -07002317 }
Romain Guy2d614592010-06-09 18:21:37 -07002318}