blob: 4bbf1a614a84442f728a43b0f55ab28abbf1ef98 [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 Guy11cb6422012-09-21 00:39:43 -0700454 */
455 abstract void pushLayerUpdate(HardwareLayer layer);
456
457 /**
Romain Guy40543602013-06-12 15:31:28 -0700458 * Forces all enqueued layer updates to be executed immediately.
459 *
460 * @see #pushLayerUpdate(HardwareLayer)
461 */
462 abstract void flushLayerUpdates();
463
464 /**
Romain Guy069ea0e2011-02-08 12:24:52 -0800465 * Interface used to receive callbacks whenever a view is drawn by
466 * a hardware renderer instance.
467 */
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800468 interface HardwareDrawCallbacks {
Romain Guy069ea0e2011-02-08 12:24:52 -0800469 /**
470 * Invoked before a view is drawn by a hardware renderer.
Romain Guy96885eb2013-03-26 15:05:58 -0700471 * This method can be used to apply transformations to the
472 * canvas but no drawing command should be issued.
Romain Guy069ea0e2011-02-08 12:24:52 -0800473 *
474 * @param canvas The Canvas used to render the view.
475 */
Romain Guy7d70fbf2011-05-24 17:40:25 -0700476 void onHardwarePreDraw(HardwareCanvas canvas);
Romain Guy069ea0e2011-02-08 12:24:52 -0800477
478 /**
479 * Invoked after a view is drawn by a hardware renderer.
Romain Guy96885eb2013-03-26 15:05:58 -0700480 * It is safe to invoke drawing commands from this method.
Romain Guy069ea0e2011-02-08 12:24:52 -0800481 *
482 * @param canvas The Canvas used to render the view.
483 */
Romain Guy7d70fbf2011-05-24 17:40:25 -0700484 void onHardwarePostDraw(HardwareCanvas canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800485 }
486
Romain Guy2d614592010-06-09 18:21:37 -0700487 /**
488 * Draws the specified view.
Romain Guy7d7b5492011-01-24 16:33:45 -0800489 *
Romain Guy2d614592010-06-09 18:21:37 -0700490 * @param view The view to draw.
491 * @param attachInfo AttachInfo tied to the specified view.
Romain Guy7d7b5492011-01-24 16:33:45 -0800492 * @param callbacks Callbacks invoked when drawing happens.
493 * @param dirty The dirty rectangle to update, can be null.
Romain Guy2d614592010-06-09 18:21:37 -0700494 */
Romain Guye55945e2013-04-04 15:26:04 -0700495 abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Romain Guy7d7b5492011-01-24 16:33:45 -0800496 Rect dirty);
Romain Guy2d614592010-06-09 18:21:37 -0700497
498 /**
Romain Guy53ca03d2010-10-08 18:55:27 -0700499 * Creates a new display list that can be used to record batches of
500 * drawing operations.
Romain Guyb051e892010-09-28 19:09:36 -0700501 *
Romain Guy52036b12013-02-14 18:03:37 -0800502 * @param name The name of the display list, used for debugging purpose. May be null.
Romain Guy13631f32012-01-30 17:41:55 -0800503 *
Romain Guy53ca03d2010-10-08 18:55:27 -0700504 * @return A new display list.
Romain Guy52036b12013-02-14 18:03:37 -0800505 *
506 * @hide
Romain Guyb051e892010-09-28 19:09:36 -0700507 */
Romain Guy13631f32012-01-30 17:41:55 -0800508 public abstract DisplayList createDisplayList(String name);
Romain Guyb051e892010-09-28 19:09:36 -0700509
510 /**
Romain Guyaa6c24c2011-04-28 18:40:04 -0700511 * Creates a new hardware layer. A hardware layer built by calling this
512 * method will be treated as a texture layer, instead of as a render target.
513 *
Romain Guya9489272011-06-22 20:58:11 -0700514 * @param isOpaque Whether the layer should be opaque or not
515 *
Romain Guyaa6c24c2011-04-28 18:40:04 -0700516 * @return A hardware layer
Jamie Gennis2af35242012-04-05 11:44:30 -0700517 */
Romain Guya9489272011-06-22 20:58:11 -0700518 abstract HardwareLayer createHardwareLayer(boolean isOpaque);
Jamie Gennis2af35242012-04-05 11:44:30 -0700519
Romain Guyaa6c24c2011-04-28 18:40:04 -0700520 /**
Romain Guy6c319ca2011-01-11 14:29:25 -0800521 * Creates a new hardware layer.
522 *
523 * @param width The minimum width of the layer
524 * @param height The minimum height of the layer
525 * @param isOpaque Whether the layer should be opaque or not
526 *
527 * @return A hardware layer
528 */
529 abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700530
531 /**
532 * Creates a new {@link SurfaceTexture} that can be used to render into the
533 * specified hardware layer.
Romain Guyaa6c24c2011-04-28 18:40:04 -0700534 *
535 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
536 *
537 * @return A {@link SurfaceTexture}
538 */
Romain Guye5e0c502011-06-15 15:18:31 -0700539 abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700540
541 /**
Jamie Gennis2af35242012-04-05 11:44:30 -0700542 * Sets the {@link android.graphics.SurfaceTexture} that will be used to
543 * render into the specified hardware layer.
544 *
545 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
546 * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer
547 */
548 abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture);
549
550 /**
Romain Guyba6be8a2012-04-23 18:22:09 -0700551 * Detaches the specified functor from the current functor execution queue.
552 *
553 * @param functor The native functor to remove from the execution queue.
554 *
555 * @see HardwareCanvas#callDrawGLFunction(int)
556 * @see #attachFunctor(android.view.View.AttachInfo, int)
557 */
558 abstract void detachFunctor(int functor);
559
560 /**
561 * Schedules the specified functor in the functors execution queue.
562 *
563 * @param attachInfo AttachInfo tied to this renderer.
564 * @param functor The native functor to insert in the execution queue.
565 *
566 * @see HardwareCanvas#callDrawGLFunction(int)
Chris Craik41ee4652012-05-31 15:05:57 -0700567 * @see #detachFunctor(int)
568 *
569 * @return true if the functor was attached successfully
Romain Guyba6be8a2012-04-23 18:22:09 -0700570 */
Chris Craik41ee4652012-05-31 15:05:57 -0700571 abstract boolean attachFunctor(View.AttachInfo attachInfo, int functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700572
573 /**
Romain Guy2d614592010-06-09 18:21:37 -0700574 * Initializes the hardware renderer for the specified surface and setup the
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700575 * renderer for drawing, if needed. This is invoked when the ViewAncestor has
Romain Guy2d614592010-06-09 18:21:37 -0700576 * potentially lost the hardware renderer. The hardware renderer should be
577 * reinitialized and setup when the render {@link #isRequested()} and
578 * {@link #isEnabled()}.
Romain Guy44d79742012-01-13 12:12:09 -0800579 *
Romain Guy2d614592010-06-09 18:21:37 -0700580 * @param width The width of the drawing surface.
581 * @param height The height of the drawing surface.
Romain Guy786fc932012-07-24 16:24:56 -0700582 * @param surface The surface to hardware accelerate
Romain Guydfab3632012-10-03 14:53:25 -0700583 *
584 * @return true if the surface was initialized, false otherwise. Returning
585 * false might mean that the surface was already initialized.
Romain Guy2d614592010-06-09 18:21:37 -0700586 */
Romain Guydfab3632012-10-03 14:53:25 -0700587 boolean initializeIfNeeded(int width, int height, Surface surface)
Romain Guy44d79742012-01-13 12:12:09 -0800588 throws Surface.OutOfResourcesException {
Romain Guy2d614592010-06-09 18:21:37 -0700589 if (isRequested()) {
590 // We lost the gl context, so recreate it.
591 if (!isEnabled()) {
Romain Guy786fc932012-07-24 16:24:56 -0700592 if (initialize(surface)) {
Romain Guyfb8b7632010-08-23 21:05:08 -0700593 setup(width, height);
Romain Guydfab3632012-10-03 14:53:25 -0700594 return true;
Romain Guy2d614592010-06-09 18:21:37 -0700595 }
596 }
Romain Guydfab3632012-10-03 14:53:25 -0700597 }
598 return false;
Romain Guy2d614592010-06-09 18:21:37 -0700599 }
600
601 /**
Romain Guyef359272013-01-31 19:07:29 -0800602 * Optional, sets the name of the renderer. Useful for debugging purposes.
603 *
604 * @param name The name of this renderer, can be null
605 */
606 abstract void setName(String name);
607
608 /**
Romain Guy2d614592010-06-09 18:21:37 -0700609 * Creates a hardware renderer using OpenGL.
610 *
611 * @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 -0700612 * @param translucent True if the surface is translucent, false otherwise
Romain Guy2d614592010-06-09 18:21:37 -0700613 *
614 * @return A hardware renderer backed by OpenGL.
615 */
Romain Guye4d01122010-06-16 18:44:05 -0700616 static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
Romain Guy2d614592010-06-09 18:21:37 -0700617 switch (glVersion) {
Romain Guye3924992010-06-10 18:51:21 -0700618 case 2:
Romain Guy16393512010-08-08 00:14:31 -0700619 return Gl20Renderer.create(translucent);
Romain Guy2d614592010-06-09 18:21:37 -0700620 }
621 throw new IllegalArgumentException("Unknown GL version: " + glVersion);
622 }
623
624 /**
Romain Guybdf76092011-07-18 15:00:43 -0700625 * Invoke this method when the system is running out of memory. This
626 * method will attempt to recover as much memory as possible, based on
627 * the specified hint.
628 *
629 * @param level Hint about the amount of memory that should be trimmed,
630 * see {@link android.content.ComponentCallbacks}
631 */
632 static void trimMemory(int level) {
Romain Guy19f86e82012-04-23 15:19:07 -0700633 startTrimMemory(level);
634 endTrimMemory();
635 }
636
637 /**
638 * Starts the process of trimming memory. Usually this call will setup
639 * hardware rendering context and reclaim memory.Extra cleanup might
640 * be required by calling {@link #endTrimMemory()}.
641 *
642 * @param level Hint about the amount of memory that should be trimmed,
643 * see {@link android.content.ComponentCallbacks}
644 */
645 static void startTrimMemory(int level) {
646 Gl20Renderer.startTrimMemory(level);
647 }
648
649 /**
650 * Finishes the process of trimming memory. This method will usually
651 * cleanup special resources used by the memory trimming process.
652 */
653 static void endTrimMemory() {
654 Gl20Renderer.endTrimMemory();
Romain Guybdf76092011-07-18 15:00:43 -0700655 }
656
657 /**
Romain Guy2d614592010-06-09 18:21:37 -0700658 * Indicates whether hardware acceleration is currently enabled.
659 *
660 * @return True if hardware acceleration is in use, false otherwise.
661 */
662 boolean isEnabled() {
663 return mEnabled;
664 }
665
666 /**
667 * Indicates whether hardware acceleration is currently enabled.
668 *
669 * @param enabled True if the hardware renderer is in use, false otherwise.
670 */
671 void setEnabled(boolean enabled) {
672 mEnabled = enabled;
673 }
674
675 /**
676 * Indicates whether hardware acceleration is currently request but not
677 * necessarily enabled yet.
678 *
679 * @return True if requested, false otherwise.
680 */
681 boolean isRequested() {
682 return mRequested;
683 }
684
685 /**
Romain Guy9745fae2010-12-08 11:39:15 -0800686 * Indicates whether hardware acceleration is currently requested but not
Romain Guy2d614592010-06-09 18:21:37 -0700687 * necessarily enabled yet.
688 *
689 * @return True to request hardware acceleration, false otherwise.
690 */
691 void setRequested(boolean requested) {
692 mRequested = requested;
693 }
694
Romain Guy48ef4a92013-01-10 18:38:46 -0800695 /**
696 * Describes a series of frames that should be drawn on screen as a graph.
697 * Each frame is composed of 1 or more elements.
698 */
699 abstract class GraphDataProvider {
700 /**
701 * Draws the graph as bars. Frame elements are stacked on top of
702 * each other.
703 */
704 public static final int GRAPH_TYPE_BARS = 0;
705 /**
706 * Draws the graph as lines. The number of series drawn corresponds
707 * to the number of elements.
708 */
709 public static final int GRAPH_TYPE_LINES = 1;
710
711 /**
712 * Returns the type of graph to render.
713 *
714 * @return {@link #GRAPH_TYPE_BARS} or {@link #GRAPH_TYPE_LINES}
715 */
716 abstract int getGraphType();
717
718 /**
719 * This method is invoked before the graph is drawn. This method
720 * can be used to compute sizes, etc.
721 *
722 * @param metrics The display metrics
723 */
724 abstract void prepare(DisplayMetrics metrics);
725
726 /**
727 * @return The size in pixels of a vertical unit.
728 */
729 abstract int getVerticalUnitSize();
730
731 /**
732 * @return The size in pixels of a horizontal unit.
733 */
734 abstract int getHorizontalUnitSize();
735
736 /**
737 * @return The size in pixels of the margin between horizontal units.
738 */
739 abstract int getHorizontaUnitMargin();
740
741 /**
742 * An optional threshold value.
743 *
744 * @return A value >= 0 to draw the threshold, a negative value
745 * to ignore it.
746 */
747 abstract float getThreshold();
748
749 /**
750 * The data to draw in the graph. The number of elements in the
751 * array must be at least {@link #getFrameCount()} * {@link #getElementCount()}.
752 * If a value is negative the following values will be ignored.
753 */
754 abstract float[] getData();
755
756 /**
757 * Returns the number of frames to render in the graph.
758 */
759 abstract int getFrameCount();
760
761 /**
762 * Returns the number of elements in each frame. This directly affects
763 * the number of series drawn in the graph.
764 */
765 abstract int getElementCount();
766
767 /**
768 * Returns the current frame, if any. If the returned value is negative
769 * the current frame is ignored.
770 */
771 abstract int getCurrentFrame();
772
773 /**
774 * Prepares the paint to draw the specified element (or series.)
775 */
776 abstract void setupGraphPaint(Paint paint, int elementIndex);
777
778 /**
779 * Prepares the paint to draw the threshold.
780 */
781 abstract void setupThresholdPaint(Paint paint);
782
783 /**
784 * Prepares the paint to draw the current frame indicator.
785 */
786 abstract void setupCurrentFramePaint(Paint paint);
787 }
788
Romain Guy2d614592010-06-09 18:21:37 -0700789 @SuppressWarnings({"deprecation"})
Romain Guye3924992010-06-10 18:51:21 -0700790 static abstract class GlRenderer extends HardwareRenderer {
Romain Guy16260e72011-09-01 14:26:11 -0700791 static final int SURFACE_STATE_ERROR = 0;
792 static final int SURFACE_STATE_SUCCESS = 1;
793 static final int SURFACE_STATE_UPDATED = 2;
Romain Guy8f3b8e32012-03-27 16:33:45 -0700794
Chris Craik65924a32012-04-05 17:52:11 -0700795 static final int FUNCTOR_PROCESS_DELAY = 4;
Romain Guy8f3b8e32012-03-27 16:33:45 -0700796
Romain Guy48ef4a92013-01-10 18:38:46 -0800797 private static final int PROFILE_DRAW_MARGIN = 0;
798 private static final int PROFILE_DRAW_WIDTH = 3;
799 private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
800 private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
801 private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
802 private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
803 private static final int PROFILE_DRAW_DP_PER_MS = 7;
804
Romain Guy78dd96d2013-05-03 14:24:16 -0700805 private static final String[] VISUALIZERS = {
806 PROFILE_PROPERTY_VISUALIZE_BARS,
807 PROFILE_PROPERTY_VISUALIZE_LINES
808 };
809
810 private static final String[] OVERDRAW = {
811 OVERDRAW_PROPERTY_SHOW,
812 OVERDRAW_PROPERTY_COUNT
813 };
814 private static final int OVERDRAW_TYPE_COUNT = 1;
815
Romain Guyfb8b7632010-08-23 21:05:08 -0700816 static EGL10 sEgl;
817 static EGLDisplay sEglDisplay;
818 static EGLConfig sEglConfig;
Romain Guy566b3ef2011-07-18 18:38:12 -0700819 static final Object[] sEglLock = new Object[0];
Chet Haase40e03832011-10-06 08:34:13 -0700820 int mWidth = -1, mHeight = -1;
Romain Guy2d614592010-06-09 18:21:37 -0700821
Romain Guy5d6999e2012-03-22 19:15:04 -0700822 static final ThreadLocal<ManagedEGLContext> sEglContextStorage
823 = new ThreadLocal<ManagedEGLContext>();
Romain Guy566b3ef2011-07-18 18:38:12 -0700824
825 EGLContext mEglContext;
826 Thread mEglThread;
Romain Guyfb8b7632010-08-23 21:05:08 -0700827
828 EGLSurface mEglSurface;
829
Romain Guye3924992010-06-10 18:51:21 -0700830 GL mGl;
Romain Guy67f27952010-12-07 20:09:23 -0800831 HardwareCanvas mCanvas;
Romain Guya676ad72012-02-13 17:47:10 -0800832
Romain Guyef359272013-01-31 19:07:29 -0800833 String mName;
834
Michael Jurkaa3fabff2012-03-28 17:22:29 +0200835 long mFrameCount;
Romain Guy7d7b5492011-01-24 16:33:45 -0800836 Paint mDebugPaint;
837
Romain Guy7e1160e2011-07-08 15:49:50 -0700838 static boolean sDirtyRegions;
839 static final boolean sDirtyRegionsRequested;
840 static {
841 String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
842 //noinspection PointlessBooleanExpression,ConstantConditions
843 sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
844 sDirtyRegionsRequested = sDirtyRegions;
845 }
846
847 boolean mDirtyRegionsEnabled;
Romain Guy9477c6e2011-12-09 12:27:21 -0800848 boolean mUpdateDirtyRegions;
849
Romain Guy5bb3c732012-11-29 17:52:58 -0800850 boolean mProfileEnabled;
Romain Guy48ef4a92013-01-10 18:38:46 -0800851 int mProfileVisualizerType = -1;
Romain Guy5bb3c732012-11-29 17:52:58 -0800852 float[] mProfileData;
853 ReentrantLock mProfileLock;
Romain Guya676ad72012-02-13 17:47:10 -0800854 int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
Romain Guy672433d2013-01-04 19:05:13 -0800855
Romain Guy48ef4a92013-01-10 18:38:46 -0800856 GraphDataProvider mDebugDataProvider;
857 float[][] mProfileShapes;
Romain Guy672433d2013-01-04 19:05:13 -0800858 Paint mProfilePaint;
859
Romain Guy5bb3c732012-11-29 17:52:58 -0800860 boolean mDebugDirtyRegions;
Romain Guy78dd96d2013-05-03 14:24:16 -0700861 int mDebugOverdraw = -1;
862 HardwareLayer mDebugOverdrawLayer;
863 Paint mDebugOverdrawPaint;
Romain Guya676ad72012-02-13 17:47:10 -0800864
Romain Guye4d01122010-06-16 18:44:05 -0700865 final int mGlVersion;
866 final boolean mTranslucent;
Romain Guye3924992010-06-10 18:51:21 -0700867
Romain Guyfb8b7632010-08-23 21:05:08 -0700868 private boolean mDestroyed;
Romain Guy566b3ef2011-07-18 18:38:12 -0700869
Romain Guycabfcc12011-03-07 18:06:46 -0800870 private final Rect mRedrawClip = new Rect();
Romain Guy8f3b8e32012-03-27 16:33:45 -0700871
Romain Guy76878822012-03-30 14:54:22 -0700872 private final int[] mSurfaceSize = new int[2];
Romain Guy8f3b8e32012-03-27 16:33:45 -0700873 private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
Romain Guyfb8b7632010-08-23 21:05:08 -0700874
Romain Guye9bc11f2013-05-23 12:47:26 -0700875 private long mDrawDelta = Long.MAX_VALUE;
876
Romain Guye4d01122010-06-16 18:44:05 -0700877 GlRenderer(int glVersion, boolean translucent) {
Romain Guye3924992010-06-10 18:51:21 -0700878 mGlVersion = glVersion;
Romain Guye4d01122010-06-16 18:44:05 -0700879 mTranslucent = translucent;
Romain Guy9ace8f52011-07-07 20:50:11 -0700880
Romain Guy5bb3c732012-11-29 17:52:58 -0800881 loadSystemProperties(null);
882 }
Romain Guya676ad72012-02-13 17:47:10 -0800883
Romain Guy5bb3c732012-11-29 17:52:58 -0800884 @Override
885 boolean loadSystemProperties(Surface surface) {
Romain Guya4fef022013-01-07 11:18:38 -0800886 boolean value;
Romain Guy5bb3c732012-11-29 17:52:58 -0800887 boolean changed = false;
888
Romain Guya4fef022013-01-07 11:18:38 -0800889 String profiling = SystemProperties.get(PROFILE_PROPERTY);
Romain Guy78dd96d2013-05-03 14:24:16 -0700890 int graphType = search(VISUALIZERS, profiling);
Romain Guy48ef4a92013-01-10 18:38:46 -0800891 value = graphType >= 0;
Romain Guya4fef022013-01-07 11:18:38 -0800892
Romain Guy48ef4a92013-01-10 18:38:46 -0800893 if (graphType != mProfileVisualizerType) {
Romain Guya4fef022013-01-07 11:18:38 -0800894 changed = true;
Romain Guy48ef4a92013-01-10 18:38:46 -0800895 mProfileVisualizerType = graphType;
Romain Guya4fef022013-01-07 11:18:38 -0800896
Romain Guy48ef4a92013-01-10 18:38:46 -0800897 mProfileShapes = null;
Romain Guya4fef022013-01-07 11:18:38 -0800898 mProfilePaint = null;
Romain Guy48ef4a92013-01-10 18:38:46 -0800899
900 if (value) {
901 mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
902 } else {
903 mDebugDataProvider = null;
904 }
Romain Guya4fef022013-01-07 11:18:38 -0800905 }
906
907 // If on-screen profiling is not enabled, we need to check whether
908 // console profiling only is enabled
909 if (!value) {
910 value = Boolean.parseBoolean(profiling);
911 }
912
Romain Guy5bb3c732012-11-29 17:52:58 -0800913 if (value != mProfileEnabled) {
914 changed = true;
915 mProfileEnabled = value;
916
917 if (mProfileEnabled) {
918 Log.d(LOG_TAG, "Profiling hardware renderer");
Romain Guy77e67cf2012-06-19 16:38:50 -0700919
Romain Guy5bb3c732012-11-29 17:52:58 -0800920 int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY,
921 PROFILE_MAX_FRAMES);
922 mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
923 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
924 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
925 }
926
927 mProfileLock = new ReentrantLock();
928 } else {
929 mProfileData = null;
930 mProfileLock = null;
Romain Guy48ef4a92013-01-10 18:38:46 -0800931 mProfileVisualizerType = -1;
Romain Guy5bb3c732012-11-29 17:52:58 -0800932 }
Romain Guy672433d2013-01-04 19:05:13 -0800933
Romain Guy666d5da2013-01-07 11:29:14 -0800934 mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
Romain Guy672433d2013-01-04 19:05:13 -0800935 }
936
Romain Guy5bb3c732012-11-29 17:52:58 -0800937 value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
938 if (value != mDebugDirtyRegions) {
939 changed = true;
940 mDebugDirtyRegions = value;
941
942 if (mDebugDirtyRegions) {
943 Log.d(LOG_TAG, "Debugging dirty regions");
944 }
Romain Guyb04f7e92012-02-15 12:36:54 -0800945 }
Romain Guy7c450aa2012-09-21 19:15:00 -0700946
Romain Guy78dd96d2013-05-03 14:24:16 -0700947 String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY);
948 int debugOverdraw = search(OVERDRAW, overdraw);
949 if (debugOverdraw != mDebugOverdraw) {
Romain Guy5bb3c732012-11-29 17:52:58 -0800950 changed = true;
Romain Guy78dd96d2013-05-03 14:24:16 -0700951 mDebugOverdraw = debugOverdraw;
952
953 if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
954 if (mDebugOverdrawLayer != null) {
955 mDebugOverdrawLayer.destroy();
956 mDebugOverdrawLayer = null;
957 mDebugOverdrawPaint = null;
958 }
959 }
Romain Guy5bb3c732012-11-29 17:52:58 -0800960 }
961
962 if (nLoadProperties()) {
963 changed = true;
964 }
965
966 return changed;
Romain Guya676ad72012-02-13 17:47:10 -0800967 }
968
Romain Guy78dd96d2013-05-03 14:24:16 -0700969 private static int search(String[] values, String value) {
970 for (int i = 0; i < values.length; i++) {
971 if (values[i].equals(value)) return i;
972 }
973 return -1;
974 }
975
Romain Guya676ad72012-02-13 17:47:10 -0800976 @Override
977 void dumpGfxInfo(PrintWriter pw) {
978 if (mProfileEnabled) {
979 pw.printf("\n\tDraw\tProcess\tExecute\n");
Romain Guy77e67cf2012-06-19 16:38:50 -0700980
981 mProfileLock.lock();
982 try {
983 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
984 if (mProfileData[i] < 0) {
985 break;
986 }
987 pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
988 mProfileData[i + 2]);
989 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
Chet Haase09280602012-04-03 16:15:34 -0700990 }
Romain Guy77e67cf2012-06-19 16:38:50 -0700991 mProfileCurrentFrame = mProfileData.length;
992 } finally {
993 mProfileLock.unlock();
Romain Guya676ad72012-02-13 17:47:10 -0800994 }
995 }
Romain Guy2d614592010-06-09 18:21:37 -0700996 }
997
Michael Jurkaa3fabff2012-03-28 17:22:29 +0200998 @Override
999 long getFrameCount() {
1000 return mFrameCount;
1001 }
1002
Romain Guye3924992010-06-10 18:51:21 -07001003 /**
Romain Guy02ccac62011-06-24 13:20:23 -07001004 * Indicates whether this renderer instance can track and update dirty regions.
1005 */
1006 boolean hasDirtyRegions() {
Romain Guy7e1160e2011-07-08 15:49:50 -07001007 return mDirtyRegionsEnabled;
Romain Guy02ccac62011-06-24 13:20:23 -07001008 }
1009
1010 /**
Romain Guy4caa4ed2010-08-25 14:46:24 -07001011 * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
Romain Guye3924992010-06-10 18:51:21 -07001012 * is invoked and the requested flag is turned off. The error code is
1013 * also logged as a warning.
1014 */
Romain Guyb025b9c2010-09-16 14:16:48 -07001015 void checkEglErrors() {
Romain Guy2d614592010-06-09 18:21:37 -07001016 if (isEnabled()) {
Romain Guy740ee652012-09-17 18:11:40 -07001017 checkEglErrorsForced();
1018 }
1019 }
1020
1021 private void checkEglErrorsForced() {
1022 int error = sEgl.eglGetError();
1023 if (error != EGL_SUCCESS) {
1024 // something bad has happened revert to
1025 // normal rendering.
1026 Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
1027 fallback(error != EGL11.EGL_CONTEXT_LOST);
Romain Guy2d614592010-06-09 18:21:37 -07001028 }
1029 }
Romain Guy67f27952010-12-07 20:09:23 -08001030
Romain Guy9745fae2010-12-08 11:39:15 -08001031 private void fallback(boolean fallback) {
1032 destroy(true);
1033 if (fallback) {
1034 // we'll try again if it was context lost
1035 setRequested(false);
Romain Guy3b748a42013-04-17 18:54:38 -07001036 Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
Romain Guy9745fae2010-12-08 11:39:15 -08001037 + "Switching back to software rendering.");
1038 }
1039 }
1040
Romain Guy2d614592010-06-09 18:21:37 -07001041 @Override
Romain Guy786fc932012-07-24 16:24:56 -07001042 boolean initialize(Surface surface) throws Surface.OutOfResourcesException {
Romain Guy2d614592010-06-09 18:21:37 -07001043 if (isRequested() && !isEnabled()) {
Romain Guy3b748a42013-04-17 18:54:38 -07001044 boolean contextCreated = initializeEgl();
Romain Guy786fc932012-07-24 16:24:56 -07001045 mGl = createEglSurface(surface);
Romain Guyfb8b7632010-08-23 21:05:08 -07001046 mDestroyed = false;
Romain Guye3924992010-06-10 18:51:21 -07001047
1048 if (mGl != null) {
Romain Guyfb8b7632010-08-23 21:05:08 -07001049 int err = sEgl.eglGetError();
Romain Guy484c7192011-07-25 11:56:33 -07001050 if (err != EGL_SUCCESS) {
Romain Guy4caa4ed2010-08-25 14:46:24 -07001051 destroy(true);
Romain Guye3924992010-06-10 18:51:21 -07001052 setRequested(false);
1053 } else {
Romain Guy4caa4ed2010-08-25 14:46:24 -07001054 if (mCanvas == null) {
1055 mCanvas = createCanvas();
Romain Guyef359272013-01-31 19:07:29 -08001056 mCanvas.setName(mName);
Romain Guyfb8b7632010-08-23 21:05:08 -07001057 }
Romain Guye55945e2013-04-04 15:26:04 -07001058 setEnabled(true);
Romain Guy3b748a42013-04-17 18:54:38 -07001059
1060 if (contextCreated) {
1061 initAtlas();
1062 }
Romain Guye3924992010-06-10 18:51:21 -07001063 }
1064
1065 return mCanvas != null;
1066 }
Romain Guy2d614592010-06-09 18:21:37 -07001067 }
1068 return false;
1069 }
Romain Guy2a83f002011-01-18 18:28:21 -08001070
1071 @Override
Romain Guy786fc932012-07-24 16:24:56 -07001072 void updateSurface(Surface surface) throws Surface.OutOfResourcesException {
Romain Guy2a83f002011-01-18 18:28:21 -08001073 if (isRequested() && isEnabled()) {
Romain Guy786fc932012-07-24 16:24:56 -07001074 createEglSurface(surface);
Romain Guy2a83f002011-01-18 18:28:21 -08001075 }
1076 }
Romain Guy2d614592010-06-09 18:21:37 -07001077
Romain Guy5d6999e2012-03-22 19:15:04 -07001078 abstract HardwareCanvas createCanvas();
Romain Guye3924992010-06-10 18:51:21 -07001079
Romain Guy29d23ec2011-07-25 14:42:24 -07001080 abstract int[] getConfig(boolean dirtyRegions);
1081
Romain Guy3b748a42013-04-17 18:54:38 -07001082 boolean initializeEgl() {
Romain Guy566b3ef2011-07-18 18:38:12 -07001083 synchronized (sEglLock) {
1084 if (sEgl == null && sEglConfig == null) {
1085 sEgl = (EGL10) EGLContext.getEGL();
1086
1087 // Get to the default display.
Romain Guy484c7192011-07-25 11:56:33 -07001088 sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
Romain Guy566b3ef2011-07-18 18:38:12 -07001089
Romain Guy484c7192011-07-25 11:56:33 -07001090 if (sEglDisplay == EGL_NO_DISPLAY) {
Romain Guy566b3ef2011-07-18 18:38:12 -07001091 throw new RuntimeException("eglGetDisplay failed "
Romain Guy407ec782011-08-24 17:06:58 -07001092 + GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guy566b3ef2011-07-18 18:38:12 -07001093 }
1094
1095 // We can now initialize EGL for that display
1096 int[] version = new int[2];
1097 if (!sEgl.eglInitialize(sEglDisplay, version)) {
1098 throw new RuntimeException("eglInitialize failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001099 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guy566b3ef2011-07-18 18:38:12 -07001100 }
Romain Guy740ee652012-09-17 18:11:40 -07001101
1102 checkEglErrorsForced();
1103
Romain Guy5bb3c732012-11-29 17:52:58 -08001104 sEglConfig = loadEglConfig();
Romain Guy069ea0e2011-02-08 12:24:52 -08001105 }
1106 }
Romain Guy566b3ef2011-07-18 18:38:12 -07001107
Romain Guy5d6999e2012-03-22 19:15:04 -07001108 ManagedEGLContext managedContext = sEglContextStorage.get();
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001109 mEglContext = managedContext != null ? managedContext.getContext() : null;
Romain Guy566b3ef2011-07-18 18:38:12 -07001110 mEglThread = Thread.currentThread();
1111
1112 if (mEglContext == null) {
1113 mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
Romain Guy5d6999e2012-03-22 19:15:04 -07001114 sEglContextStorage.set(createManagedContext(mEglContext));
Romain Guy3b748a42013-04-17 18:54:38 -07001115 return true;
Romain Guy566b3ef2011-07-18 18:38:12 -07001116 }
Romain Guy3b748a42013-04-17 18:54:38 -07001117
1118 return false;
Romain Guy2d614592010-06-09 18:21:37 -07001119 }
1120
Romain Guy5bb3c732012-11-29 17:52:58 -08001121 private EGLConfig loadEglConfig() {
1122 EGLConfig eglConfig = chooseEglConfig();
1123 if (eglConfig == null) {
1124 // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
1125 if (sDirtyRegions) {
1126 sDirtyRegions = false;
1127 eglConfig = chooseEglConfig();
1128 if (eglConfig == null) {
1129 throw new RuntimeException("eglConfig not initialized");
1130 }
1131 } else {
1132 throw new RuntimeException("eglConfig not initialized");
1133 }
1134 }
1135 return eglConfig;
1136 }
1137
Romain Guy5d6999e2012-03-22 19:15:04 -07001138 abstract ManagedEGLContext createManagedContext(EGLContext eglContext);
1139
Romain Guye91a9c72011-05-02 14:53:30 -07001140 private EGLConfig chooseEglConfig() {
Romain Guye91a9c72011-05-02 14:53:30 -07001141 EGLConfig[] configs = new EGLConfig[1];
Romain Guy484c7192011-07-25 11:56:33 -07001142 int[] configsCount = new int[1];
Romain Guy7e1160e2011-07-08 15:49:50 -07001143 int[] configSpec = getConfig(sDirtyRegions);
Romain Guy484c7192011-07-25 11:56:33 -07001144
1145 // Debug
Romain Guy29d23ec2011-07-25 14:42:24 -07001146 final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
Romain Guy484c7192011-07-25 11:56:33 -07001147 if ("all".equalsIgnoreCase(debug)) {
1148 sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
1149
1150 EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
1151 sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
1152 configsCount[0], configsCount);
1153
1154 for (EGLConfig config : debugConfigs) {
1155 printConfig(config);
1156 }
1157 }
1158
Romain Guye91a9c72011-05-02 14:53:30 -07001159 if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
1160 throw new IllegalArgumentException("eglChooseConfig failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001161 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guye91a9c72011-05-02 14:53:30 -07001162 } else if (configsCount[0] > 0) {
Romain Guy484c7192011-07-25 11:56:33 -07001163 if ("choice".equalsIgnoreCase(debug)) {
1164 printConfig(configs[0]);
1165 }
Romain Guye91a9c72011-05-02 14:53:30 -07001166 return configs[0];
1167 }
Romain Guy484c7192011-07-25 11:56:33 -07001168
Romain Guye91a9c72011-05-02 14:53:30 -07001169 return null;
1170 }
1171
Romain Guye979e622012-03-20 13:50:27 -07001172 private static void printConfig(EGLConfig config) {
Romain Guy484c7192011-07-25 11:56:33 -07001173 int[] value = new int[1];
1174
1175 Log.d(LOG_TAG, "EGL configuration " + config + ":");
1176
1177 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
1178 Log.d(LOG_TAG, " RED_SIZE = " + value[0]);
1179
1180 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
1181 Log.d(LOG_TAG, " GREEN_SIZE = " + value[0]);
1182
1183 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
1184 Log.d(LOG_TAG, " BLUE_SIZE = " + value[0]);
1185
1186 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
1187 Log.d(LOG_TAG, " ALPHA_SIZE = " + value[0]);
1188
1189 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
1190 Log.d(LOG_TAG, " DEPTH_SIZE = " + value[0]);
1191
1192 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
1193 Log.d(LOG_TAG, " STENCIL_SIZE = " + value[0]);
1194
Romain Guy8efca542012-10-15 18:09:49 -07001195 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value);
1196 Log.d(LOG_TAG, " SAMPLE_BUFFERS = " + value[0]);
1197
1198 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value);
1199 Log.d(LOG_TAG, " SAMPLES = " + value[0]);
1200
Romain Guy484c7192011-07-25 11:56:33 -07001201 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
Romain Guy29d23ec2011-07-25 14:42:24 -07001202 Log.d(LOG_TAG, " SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
Romain Guy8efca542012-10-15 18:09:49 -07001203
1204 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value);
1205 Log.d(LOG_TAG, " CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
Romain Guy484c7192011-07-25 11:56:33 -07001206 }
1207
Romain Guy786fc932012-07-24 16:24:56 -07001208 GL createEglSurface(Surface surface) throws Surface.OutOfResourcesException {
Romain Guye3924992010-06-10 18:51:21 -07001209 // Check preconditions.
Romain Guyfb8b7632010-08-23 21:05:08 -07001210 if (sEgl == null) {
Romain Guye3924992010-06-10 18:51:21 -07001211 throw new RuntimeException("egl not initialized");
Romain Guy2d614592010-06-09 18:21:37 -07001212 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001213 if (sEglDisplay == null) {
Romain Guye3924992010-06-10 18:51:21 -07001214 throw new RuntimeException("eglDisplay not initialized");
1215 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001216 if (sEglConfig == null) {
Romain Guy069ea0e2011-02-08 12:24:52 -08001217 throw new RuntimeException("eglConfig not initialized");
Romain Guye3924992010-06-10 18:51:21 -07001218 }
Romain Guy566b3ef2011-07-18 18:38:12 -07001219 if (Thread.currentThread() != mEglThread) {
Romain Guyfb8b7632010-08-23 21:05:08 -07001220 throw new IllegalStateException("HardwareRenderer cannot be used "
1221 + "from multiple threads");
1222 }
Romain Guye3924992010-06-10 18:51:21 -07001223
Romain Guy6d7475d2011-07-27 16:28:21 -07001224 // In case we need to destroy an existing surface
1225 destroySurface();
Romain Guye3924992010-06-10 18:51:21 -07001226
1227 // Create an EGL surface we can render into.
Romain Guy786fc932012-07-24 16:24:56 -07001228 if (!createSurface(surface)) {
Romain Guy1d0c7082011-08-03 16:22:24 -07001229 return null;
Romain Guye3924992010-06-10 18:51:21 -07001230 }
1231
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001232 initCaches();
Romain Guy6f7d9392011-06-02 14:17:28 -07001233
Romain Guy9477c6e2011-12-09 12:27:21 -08001234 return mEglContext.getGL();
1235 }
1236
1237 private void enableDirtyRegions() {
Romain Guy6f7d9392011-06-02 14:17:28 -07001238 // If mDirtyRegions is set, this means we have an EGL configuration
1239 // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
Romain Guy7e1160e2011-07-08 15:49:50 -07001240 if (sDirtyRegions) {
Romain Guy244ada12012-03-28 16:41:26 -07001241 if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001242 Log.w(LOG_TAG, "Backbuffer cannot be preserved");
1243 }
Romain Guy7e1160e2011-07-08 15:49:50 -07001244 } else if (sDirtyRegionsRequested) {
Romain Guy6f7d9392011-06-02 14:17:28 -07001245 // If mDirtyRegions is not set, our EGL configuration does not
1246 // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
1247 // swap behavior might be EGL_BUFFER_PRESERVED, which means we
1248 // want to set mDirtyRegions. We try to do this only if dirty
1249 // regions were initially requested as part of the device
1250 // configuration (see RENDER_DIRTY_REGIONS)
Romain Guy244ada12012-03-28 16:41:26 -07001251 mDirtyRegionsEnabled = isBackBufferPreserved();
Romain Guy7d7b5492011-01-24 16:33:45 -08001252 }
Romain Guye3924992010-06-10 18:51:21 -07001253 }
1254
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001255 abstract void initCaches();
Romain Guy3b748a42013-04-17 18:54:38 -07001256 abstract void initAtlas();
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001257
Romain Guye3924992010-06-10 18:51:21 -07001258 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
Romain Guybd431522012-09-26 13:31:25 -07001259 int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
Romain Guye3924992010-06-10 18:51:21 -07001260
Romain Guyc0029362012-09-24 20:18:13 -07001261 EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
1262 mGlVersion != 0 ? attribs : null);
Romain Guyed1b6f42012-09-24 21:42:18 -07001263 if (context == null || context == EGL_NO_CONTEXT) {
Romain Guyc0029362012-09-24 20:18:13 -07001264 //noinspection ConstantConditions
1265 throw new IllegalStateException(
1266 "Could not create an EGL context. eglCreateContext failed with error: " +
1267 GLUtils.getEGLErrorString(sEgl.eglGetError()));
1268 }
Romain Guy3b748a42013-04-17 18:54:38 -07001269
Romain Guyc0029362012-09-24 20:18:13 -07001270 return context;
Romain Guy2d614592010-06-09 18:21:37 -07001271 }
1272
1273 @Override
Romain Guy4caa4ed2010-08-25 14:46:24 -07001274 void destroy(boolean full) {
1275 if (full && mCanvas != null) {
Romain Guy4caa4ed2010-08-25 14:46:24 -07001276 mCanvas = null;
1277 }
Romain Guye3924992010-06-10 18:51:21 -07001278
Romain Guy357c9422011-08-02 11:32:49 -07001279 if (!isEnabled() || mDestroyed) {
1280 setEnabled(false);
1281 return;
1282 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001283
Romain Guy6d7475d2011-07-27 16:28:21 -07001284 destroySurface();
Romain Guye3924992010-06-10 18:51:21 -07001285 setEnabled(false);
Romain Guy357c9422011-08-02 11:32:49 -07001286
1287 mDestroyed = true;
1288 mGl = null;
Romain Guyfb8b7632010-08-23 21:05:08 -07001289 }
1290
Romain Guy6d7475d2011-07-27 16:28:21 -07001291 void destroySurface() {
1292 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
1293 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1294 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
1295 mEglSurface = null;
1296 }
1297 }
1298
Romain Guye3924992010-06-10 18:51:21 -07001299 @Override
Romain Guy786fc932012-07-24 16:24:56 -07001300 void invalidate(Surface surface) {
Romain Guy7e1160e2011-07-08 15:49:50 -07001301 // Cancels any existing buffer to ensure we'll get a buffer
1302 // of the right size before we call eglSwapBuffers
Romain Guycf15efb2011-08-02 12:59:32 -07001303 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
Romain Guy1d0c7082011-08-03 16:22:24 -07001304
Romain Guyd3facf32011-08-03 11:14:38 -07001305 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
1306 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
Romain Guy1d0c7082011-08-03 16:22:24 -07001307 mEglSurface = null;
1308 setEnabled(false);
Romain Guyd3facf32011-08-03 11:14:38 -07001309 }
Romain Guycf15efb2011-08-02 12:59:32 -07001310
Romain Guy786fc932012-07-24 16:24:56 -07001311 if (surface.isValid()) {
1312 if (!createSurface(surface)) {
Romain Guy1d0c7082011-08-03 16:22:24 -07001313 return;
Romain Guycf15efb2011-08-02 12:59:32 -07001314 }
Romain Guy9477c6e2011-12-09 12:27:21 -08001315
1316 mUpdateDirtyRegions = true;
1317
Romain Guy86e3e222011-08-16 14:30:08 -07001318 if (mCanvas != null) {
1319 setEnabled(true);
1320 }
Romain Guycf15efb2011-08-02 12:59:32 -07001321 }
Romain Guy03985752011-07-11 15:33:51 -07001322 }
Romain Guycf15efb2011-08-02 12:59:32 -07001323
Romain Guy786fc932012-07-24 16:24:56 -07001324 private boolean createSurface(Surface surface) {
1325 mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
Romain Guy1d0c7082011-08-03 16:22:24 -07001326
1327 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
1328 int error = sEgl.eglGetError();
1329 if (error == EGL_BAD_NATIVE_WINDOW) {
1330 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
1331 return false;
1332 }
1333 throw new RuntimeException("createWindowSurface failed "
Romain Guy407ec782011-08-24 17:06:58 -07001334 + GLUtils.getEGLErrorString(error));
Romain Guy1d0c7082011-08-03 16:22:24 -07001335 }
Romain Guybd431522012-09-26 13:31:25 -07001336
1337 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
1338 throw new IllegalStateException("eglMakeCurrent failed " +
1339 GLUtils.getEGLErrorString(sEgl.eglGetError()));
1340 }
1341
1342 enableDirtyRegions();
1343
Romain Guy1d0c7082011-08-03 16:22:24 -07001344 return true;
1345 }
1346
Romain Guy03985752011-07-11 15:33:51 -07001347 @Override
1348 boolean validate() {
1349 return checkCurrent() != SURFACE_STATE_ERROR;
Romain Guy7e1160e2011-07-08 15:49:50 -07001350 }
1351
1352 @Override
Romain Guyfb8b7632010-08-23 21:05:08 -07001353 void setup(int width, int height) {
Romain Guyeca9b1f2011-08-26 13:36:37 -07001354 if (validate()) {
1355 mCanvas.setViewport(width, height);
Chet Haase40e03832011-10-06 08:34:13 -07001356 mWidth = width;
1357 mHeight = height;
Romain Guyeca9b1f2011-08-26 13:36:37 -07001358 }
Romain Guye3924992010-06-10 18:51:21 -07001359 }
Romain Guy7d7b5492011-01-24 16:33:45 -08001360
Chet Haase40e03832011-10-06 08:34:13 -07001361 @Override
1362 int getWidth() {
1363 return mWidth;
1364 }
1365
1366 @Override
1367 int getHeight() {
1368 return mHeight;
1369 }
1370
Chet Haase08837c22011-11-28 11:53:21 -08001371 @Override
1372 HardwareCanvas getCanvas() {
1373 return mCanvas;
1374 }
1375
Romain Guyef359272013-01-31 19:07:29 -08001376 @Override
1377 void setName(String name) {
1378 mName = name;
1379 }
1380
Romain Guye3924992010-06-10 18:51:21 -07001381 boolean canDraw() {
1382 return mGl != null && mCanvas != null;
1383 }
1384
Chet Haase44b2fe32012-06-06 19:03:58 -07001385 int onPreDraw(Rect dirty) {
1386 return DisplayList.STATUS_DONE;
Romain Guye3924992010-06-10 18:51:21 -07001387 }
1388
Romain Guyb025b9c2010-09-16 14:16:48 -07001389 void onPostDraw() {
1390 }
Romain Guye3924992010-06-10 18:51:21 -07001391
Romain Guy8f3b8e32012-03-27 16:33:45 -07001392 class FunctorsRunnable implements Runnable {
1393 View.AttachInfo attachInfo;
1394
1395 @Override
1396 public void run() {
1397 final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
1398 if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
1399 return;
1400 }
1401
1402 final int surfaceState = checkCurrent();
1403 if (surfaceState != SURFACE_STATE_ERROR) {
1404 int status = mCanvas.invokeFunctors(mRedrawClip);
1405 handleFunctorStatus(attachInfo, status);
1406 }
1407 }
1408 }
1409
Romain Guye3924992010-06-10 18:51:21 -07001410 @Override
Romain Guye55945e2013-04-04 15:26:04 -07001411 void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Romain Guy7d7b5492011-01-24 16:33:45 -08001412 Rect dirty) {
Romain Guye3924992010-06-10 18:51:21 -07001413 if (canDraw()) {
Romain Guy02ccac62011-06-24 13:20:23 -07001414 if (!hasDirtyRegions()) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001415 dirty = null;
1416 }
Romain Guye3924992010-06-10 18:51:21 -07001417 attachInfo.mIgnoreDirtyState = true;
Romain Guy02ccac62011-06-24 13:20:23 -07001418 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
1419
Dianne Hackborn4702a852012-08-17 15:18:29 -07001420 view.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy03985752011-07-11 15:33:51 -07001421
Romain Guyd88f54c2011-01-24 20:22:49 -08001422 final int surfaceState = checkCurrent();
1423 if (surfaceState != SURFACE_STATE_ERROR) {
Romain Guy76878822012-03-30 14:54:22 -07001424 HardwareCanvas canvas = mCanvas;
1425 attachInfo.mHardwareCanvas = canvas;
Romain Guy77e67cf2012-06-19 16:38:50 -07001426
1427 if (mProfileEnabled) {
1428 mProfileLock.lock();
1429 }
1430
Romain Guy672433d2013-01-04 19:05:13 -08001431 dirty = beginFrame(canvas, dirty, surfaceState);
Romain Guyd88f54c2011-01-24 20:22:49 -08001432
Romain Guyd17043d2013-02-19 14:12:55 -08001433 DisplayList displayList = buildDisplayList(view, canvas);
1434
Romain Guy2b7028e2012-09-19 17:25:38 -07001435 int saveCount = 0;
1436 int status = DisplayList.STATUS_DONE;
Chet Haasedaf98e92011-01-10 14:10:36 -08001437
Romain Guye9bc11f2013-05-23 12:47:26 -07001438 long start = getSystemTime();
Romain Guyb8c0de22010-12-13 14:42:34 -08001439 try {
Romain Guy672433d2013-01-04 19:05:13 -08001440 status = prepareFrame(dirty);
Jeff Brown95db2b22011-11-30 19:54:41 -08001441
Romain Guy2b7028e2012-09-19 17:25:38 -07001442 saveCount = canvas.save();
1443 callbacks.onHardwarePreDraw(canvas);
1444
Chet Haasedaf98e92011-01-10 14:10:36 -08001445 if (displayList != null) {
Chet Haase58d110a2013-04-10 07:43:29 -07001446 status |= drawDisplayList(attachInfo, canvas, displayList, status);
Chet Haasedaf98e92011-01-10 14:10:36 -08001447 } else {
1448 // Shouldn't reach here
1449 view.draw(canvas);
1450 }
Romain Guyd17043d2013-02-19 14:12:55 -08001451 } catch (Exception e) {
1452 Log.e(LOG_TAG, "An error has occurred while drawing:", e);
Romain Guyb04f7e92012-02-15 12:36:54 -08001453 } finally {
1454 callbacks.onHardwarePostDraw(canvas);
1455 canvas.restoreToCount(saveCount);
1456 view.mRecreateDisplayList = false;
Romain Guy19f86e82012-04-23 15:19:07 -07001457
Romain Guye9bc11f2013-05-23 12:47:26 -07001458 mDrawDelta = getSystemTime() - start;
Romain Guy78dd96d2013-05-03 14:24:16 -07001459
Romain Guye9bc11f2013-05-23 12:47:26 -07001460 if (mDrawDelta > 0) {
1461 mFrameCount++;
Romain Guy19f86e82012-04-23 15:19:07 -07001462
Romain Guye9bc11f2013-05-23 12:47:26 -07001463 debugOverdraw(attachInfo, dirty, canvas, displayList);
1464 debugDirtyRegions(dirty, canvas);
1465 drawProfileData(attachInfo);
1466 }
Romain Guyb8c0de22010-12-13 14:42:34 -08001467 }
Chet Haasedaf98e92011-01-10 14:10:36 -08001468
Romain Guyb8c0de22010-12-13 14:42:34 -08001469 onPostDraw();
Chet Haasedaf98e92011-01-10 14:10:36 -08001470
Romain Guy672433d2013-01-04 19:05:13 -08001471 swapBuffers(status);
Jeff Brown95db2b22011-11-30 19:54:41 -08001472
Romain Guy77e67cf2012-06-19 16:38:50 -07001473 if (mProfileEnabled) {
1474 mProfileLock.unlock();
1475 }
1476
Romain Guy672433d2013-01-04 19:05:13 -08001477 attachInfo.mIgnoreDirtyState = false;
Romain Guye3924992010-06-10 18:51:21 -07001478 }
Romain Guye3924992010-06-10 18:51:21 -07001479 }
1480 }
Romain Guy03985752011-07-11 15:33:51 -07001481
Romain Guy78dd96d2013-05-03 14:24:16 -07001482 abstract void countOverdraw(HardwareCanvas canvas);
1483 abstract float getOverdraw(HardwareCanvas canvas);
1484
1485 private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
1486 HardwareCanvas canvas, DisplayList displayList) {
1487
1488 if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
1489 // TODO: Use an alpha layer allocated from a GraphicBuffer
1490 // The alpha format will help with rendering performance and
1491 // the GraphicBuffer will let us skip the read pixels step
1492 if (mDebugOverdrawLayer == null) {
1493 mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
1494 } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
1495 mDebugOverdrawLayer.getHeight() != mHeight) {
1496 mDebugOverdrawLayer.resize(mWidth, mHeight);
1497 }
1498
1499 if (!mDebugOverdrawLayer.isValid()) {
1500 mDebugOverdraw = -1;
1501 return;
1502 }
1503
1504 HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
1505 countOverdraw(layerCanvas);
1506 final int restoreCount = layerCanvas.save();
1507 layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
1508 layerCanvas.restoreToCount(restoreCount);
1509 mDebugOverdrawLayer.end(canvas);
1510
1511 float overdraw = getOverdraw(layerCanvas);
1512 DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
1513
1514 drawOverdrawCounter(canvas, overdraw, metrics.density);
1515 }
1516 }
1517
1518 private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
1519 final String text = String.format("%.2fx", overdraw);
1520 final Paint paint = setupPaint(density);
1521 // HSBtoColor will clamp the values in the 0..1 range
1522 paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
1523
1524 canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
1525 }
1526
1527 private Paint setupPaint(float density) {
1528 if (mDebugOverdrawPaint == null) {
1529 mDebugOverdrawPaint = new Paint();
1530 mDebugOverdrawPaint.setAntiAlias(true);
1531 mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
1532 mDebugOverdrawPaint.setTextSize(density * 20.0f);
1533 }
1534 return mDebugOverdrawPaint;
1535 }
1536
Romain Guyd17043d2013-02-19 14:12:55 -08001537 private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
Romain Guye9bc11f2013-05-23 12:47:26 -07001538 if (mDrawDelta <= 0) {
1539 return view.mDisplayList;
1540 }
1541
Romain Guyd17043d2013-02-19 14:12:55 -08001542 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
1543 == View.PFLAG_INVALIDATED;
1544 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
1545
1546 long buildDisplayListStartTime = startBuildDisplayListProfiling();
1547 canvas.clearLayerUpdates();
1548
1549 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
1550 DisplayList displayList = view.getDisplayList();
1551 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1552
1553 endBuildDisplayListProfiling(buildDisplayListStartTime);
1554
1555 return displayList;
1556 }
1557
Romain Guy98e4a522013-01-07 10:58:34 -08001558 abstract void drawProfileData(View.AttachInfo attachInfo);
Romain Guy672433d2013-01-04 19:05:13 -08001559
1560 private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
1561 // We had to change the current surface and/or context, redraw everything
1562 if (surfaceState == SURFACE_STATE_UPDATED) {
1563 dirty = null;
1564 beginFrame(null);
1565 } else {
1566 int[] size = mSurfaceSize;
1567 beginFrame(size);
1568
1569 if (size[1] != mHeight || size[0] != mWidth) {
1570 mWidth = size[0];
1571 mHeight = size[1];
1572
1573 canvas.setViewport(mWidth, mHeight);
1574
1575 dirty = null;
1576 }
1577 }
1578
Romain Guy48ef4a92013-01-10 18:38:46 -08001579 if (mDebugDataProvider != null) dirty = null;
Romain Guy672433d2013-01-04 19:05:13 -08001580
1581 return dirty;
1582 }
1583
1584 private long startBuildDisplayListProfiling() {
1585 if (mProfileEnabled) {
1586 mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
1587 if (mProfileCurrentFrame >= mProfileData.length) {
1588 mProfileCurrentFrame = 0;
1589 }
1590
1591 return System.nanoTime();
1592 }
1593 return 0;
1594 }
1595
1596 private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
1597 if (mProfileEnabled) {
1598 long now = System.nanoTime();
1599 float total = (now - getDisplayListStartTime) * 0.000001f;
1600 //noinspection PointlessArithmeticExpression
1601 mProfileData[mProfileCurrentFrame] = total;
1602 }
1603 }
1604
Romain Guy672433d2013-01-04 19:05:13 -08001605 private int prepareFrame(Rect dirty) {
1606 int status;
1607 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
1608 try {
1609 status = onPreDraw(dirty);
1610 } finally {
1611 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1612 }
1613 return status;
1614 }
1615
1616 private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
1617 DisplayList displayList, int status) {
1618
1619 long drawDisplayListStartTime = 0;
1620 if (mProfileEnabled) {
1621 drawDisplayListStartTime = System.nanoTime();
1622 }
1623
1624 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
1625 try {
1626 status |= canvas.drawDisplayList(displayList, mRedrawClip,
1627 DisplayList.FLAG_CLIP_CHILDREN);
1628 } finally {
1629 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1630 }
1631
1632 if (mProfileEnabled) {
1633 long now = System.nanoTime();
1634 float total = (now - drawDisplayListStartTime) * 0.000001f;
1635 mProfileData[mProfileCurrentFrame + 1] = total;
1636 }
1637
1638 handleFunctorStatus(attachInfo, status);
1639 return status;
1640 }
1641
1642 private void swapBuffers(int status) {
1643 if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
1644 long eglSwapBuffersStartTime = 0;
1645 if (mProfileEnabled) {
1646 eglSwapBuffersStartTime = System.nanoTime();
1647 }
1648
1649 sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
1650
1651 if (mProfileEnabled) {
1652 long now = System.nanoTime();
1653 float total = (now - eglSwapBuffersStartTime) * 0.000001f;
1654 mProfileData[mProfileCurrentFrame + 2] = total;
1655 }
1656
1657 checkEglErrors();
1658 }
1659 }
1660
1661 private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
1662 if (mDebugDirtyRegions) {
1663 if (mDebugPaint == null) {
1664 mDebugPaint = new Paint();
1665 mDebugPaint.setColor(0x7fff0000);
1666 }
1667
1668 if (dirty != null && (mFrameCount & 1) == 0) {
1669 canvas.drawRect(dirty, mDebugPaint);
1670 }
1671 }
1672 }
1673
Romain Guy8f3b8e32012-03-27 16:33:45 -07001674 private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
1675 // If the draw flag is set, functors will be invoked while executing
1676 // the tree of display lists
1677 if ((status & DisplayList.STATUS_DRAW) != 0) {
1678 if (mRedrawClip.isEmpty()) {
1679 attachInfo.mViewRootImpl.invalidate();
1680 } else {
1681 attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
1682 mRedrawClip.setEmpty();
1683 }
1684 }
1685
Chris Craik9efa2222012-12-04 15:15:31 -08001686 if ((status & DisplayList.STATUS_INVOKE) != 0 ||
1687 attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
1688 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
1689 mFunctorsRunnable.attachInfo = attachInfo;
1690 attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
Romain Guy8f3b8e32012-03-27 16:33:45 -07001691 }
1692 }
1693
Romain Guyba6be8a2012-04-23 18:22:09 -07001694 @Override
1695 void detachFunctor(int functor) {
1696 if (mCanvas != null) {
1697 mCanvas.detachFunctor(functor);
Chris Craik932b7f62012-06-06 13:59:33 -07001698 }
Romain Guyba6be8a2012-04-23 18:22:09 -07001699 }
1700
1701 @Override
Chris Craik41ee4652012-05-31 15:05:57 -07001702 boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
Romain Guyba6be8a2012-04-23 18:22:09 -07001703 if (mCanvas != null) {
1704 mCanvas.attachFunctor(functor);
Chris Craik9efa2222012-12-04 15:15:31 -08001705 mFunctorsRunnable.attachInfo = attachInfo;
1706 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
1707 attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0);
Chris Craik41ee4652012-05-31 15:05:57 -07001708 return true;
Romain Guyba6be8a2012-04-23 18:22:09 -07001709 }
Chris Craik41ee4652012-05-31 15:05:57 -07001710 return false;
Romain Guyba6be8a2012-04-23 18:22:09 -07001711 }
1712
Romain Guy03985752011-07-11 15:33:51 -07001713 /**
Romain Guy566b3ef2011-07-18 18:38:12 -07001714 * Ensures the current EGL context is the one we expect.
Romain Guy03985752011-07-11 15:33:51 -07001715 *
1716 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
1717 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
1718 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
1719 */
Romain Guy912a7b32011-07-26 18:57:28 -07001720 int checkCurrent() {
Romain Guy566b3ef2011-07-18 18:38:12 -07001721 if (mEglThread != Thread.currentThread()) {
Romain Guy03985752011-07-11 15:33:51 -07001722 throw new IllegalStateException("Hardware acceleration can only be used with a " +
Romain Guy566b3ef2011-07-18 18:38:12 -07001723 "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
Romain Guy03985752011-07-11 15:33:51 -07001724 "Current thread: " + Thread.currentThread());
1725 }
1726
Romain Guy566b3ef2011-07-18 18:38:12 -07001727 if (!mEglContext.equals(sEgl.eglGetCurrentContext()) ||
Romain Guy484c7192011-07-25 11:56:33 -07001728 !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
Romain Guy566b3ef2011-07-18 18:38:12 -07001729 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
Romain Guy9745fae2010-12-08 11:39:15 -08001730 Log.e(LOG_TAG, "eglMakeCurrent failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001731 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guyeca9b1f2011-08-26 13:36:37 -07001732 fallback(true);
Romain Guyd88f54c2011-01-24 20:22:49 -08001733 return SURFACE_STATE_ERROR;
1734 } else {
Romain Guy9477c6e2011-12-09 12:27:21 -08001735 if (mUpdateDirtyRegions) {
1736 enableDirtyRegions();
1737 mUpdateDirtyRegions = false;
1738 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001739 return SURFACE_STATE_UPDATED;
Romain Guyfb8b7632010-08-23 21:05:08 -07001740 }
1741 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001742 return SURFACE_STATE_SUCCESS;
Romain Guyfb8b7632010-08-23 21:05:08 -07001743 }
Romain Guy48ef4a92013-01-10 18:38:46 -08001744
1745 private static int dpToPx(int dp, float density) {
1746 return (int) (dp * density + 0.5f);
1747 }
1748
1749 class DrawPerformanceDataProvider extends GraphDataProvider {
1750 private final int mGraphType;
1751
1752 private int mVerticalUnit;
1753 private int mHorizontalUnit;
1754 private int mHorizontalMargin;
1755 private int mThresholdStroke;
1756
1757 DrawPerformanceDataProvider(int graphType) {
1758 mGraphType = graphType;
1759 }
1760
1761 @Override
1762 void prepare(DisplayMetrics metrics) {
1763 final float density = metrics.density;
1764
1765 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
1766 mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
1767 mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
1768 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
1769 }
1770
1771 @Override
1772 int getGraphType() {
1773 return mGraphType;
1774 }
1775
1776 @Override
1777 int getVerticalUnitSize() {
1778 return mVerticalUnit;
1779 }
1780
1781 @Override
1782 int getHorizontalUnitSize() {
1783 return mHorizontalUnit;
1784 }
1785
1786 @Override
1787 int getHorizontaUnitMargin() {
1788 return mHorizontalMargin;
1789 }
1790
1791 @Override
1792 float[] getData() {
1793 return mProfileData;
1794 }
1795
1796 @Override
1797 float getThreshold() {
1798 return 16;
1799 }
1800
1801 @Override
1802 int getFrameCount() {
1803 return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
1804 }
1805
1806 @Override
1807 int getElementCount() {
1808 return PROFILE_FRAME_DATA_COUNT;
1809 }
1810
1811 @Override
1812 int getCurrentFrame() {
1813 return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
1814 }
1815
1816 @Override
1817 void setupGraphPaint(Paint paint, int elementIndex) {
1818 paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
1819 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
1820 }
1821
1822 @Override
1823 void setupThresholdPaint(Paint paint) {
1824 paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
1825 paint.setStrokeWidth(mThresholdStroke);
1826 }
1827
1828 @Override
1829 void setupCurrentFramePaint(Paint paint) {
1830 paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
1831 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
1832 }
1833 }
Romain Guye3924992010-06-10 18:51:21 -07001834 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001835
Romain Guye3924992010-06-10 18:51:21 -07001836 /**
1837 * Hardware renderer using OpenGL ES 2.0.
1838 */
1839 static class Gl20Renderer extends GlRenderer {
Romain Guye4d01122010-06-16 18:44:05 -07001840 private GLES20Canvas mGlCanvas;
1841
Romain Guy98e4a522013-01-07 10:58:34 -08001842 private DisplayMetrics mDisplayMetrics;
1843
Romain Guy912a7b32011-07-26 18:57:28 -07001844 private static EGLSurface sPbuffer;
1845 private static final Object[] sPbufferLock = new Object[0];
1846
Romain Guy31f2c2e2011-11-21 10:55:41 -08001847 static class Gl20RendererEglContext extends ManagedEGLContext {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001848 final Handler mHandler = new Handler();
1849
Romain Guy31f2c2e2011-11-21 10:55:41 -08001850 public Gl20RendererEglContext(EGLContext context) {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001851 super(context);
1852 }
1853
1854 @Override
1855 public void onTerminate(final EGLContext eglContext) {
1856 // Make sure we do this on the correct thread.
1857 if (mHandler.getLooper() != Looper.myLooper()) {
1858 mHandler.post(new Runnable() {
Romain Guy5d6999e2012-03-22 19:15:04 -07001859 @Override
1860 public void run() {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001861 onTerminate(eglContext);
1862 }
1863 });
1864 return;
1865 }
1866
1867 synchronized (sEglLock) {
1868 if (sEgl == null) return;
1869
1870 if (EGLImpl.getInitCount(sEglDisplay) == 1) {
1871 usePbufferSurface(eglContext);
1872 GLES20Canvas.terminateCaches();
1873
1874 sEgl.eglDestroyContext(sEglDisplay, eglContext);
Romain Guya998dff2012-03-23 18:58:36 -07001875 sEglContextStorage.set(null);
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001876 sEglContextStorage.remove();
1877
1878 sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
Romain Guy31f2c2e2011-11-21 10:55:41 -08001879 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
1880 EGL_NO_SURFACE, EGL_NO_CONTEXT);
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001881
1882 sEgl.eglReleaseThread();
1883 sEgl.eglTerminate(sEglDisplay);
1884
1885 sEgl = null;
1886 sEglDisplay = null;
1887 sEglConfig = null;
1888 sPbuffer = null;
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001889 }
1890 }
1891 }
1892 }
1893
Romain Guye4d01122010-06-16 18:44:05 -07001894 Gl20Renderer(boolean translucent) {
1895 super(2, translucent);
Romain Guye3924992010-06-10 18:51:21 -07001896 }
1897
1898 @Override
Romain Guy5d6999e2012-03-22 19:15:04 -07001899 HardwareCanvas createCanvas() {
Romain Guy6b7bd242010-10-06 19:49:23 -07001900 return mGlCanvas = new GLES20Canvas(mTranslucent);
Romain Guye4d01122010-06-16 18:44:05 -07001901 }
Romain Guye91a9c72011-05-02 14:53:30 -07001902
1903 @Override
Romain Guy5d6999e2012-03-22 19:15:04 -07001904 ManagedEGLContext createManagedContext(EGLContext eglContext) {
1905 return new Gl20Renderer.Gl20RendererEglContext(mEglContext);
1906 }
1907
1908 @Override
Romain Guye91a9c72011-05-02 14:53:30 -07001909 int[] getConfig(boolean dirtyRegions) {
Romain Guy8ce00302013-01-15 18:51:42 -08001910 //noinspection PointlessBooleanExpression,ConstantConditions
1911 final int stencilSize = GLES20Canvas.getStencilSize();
Romain Guy735738c2012-12-03 12:34:51 -08001912 final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
1913
Romain Guye91a9c72011-05-02 14:53:30 -07001914 return new int[] {
Romain Guybd431522012-09-26 13:31:25 -07001915 EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
Romain Guy484c7192011-07-25 11:56:33 -07001916 EGL_RED_SIZE, 8,
1917 EGL_GREEN_SIZE, 8,
1918 EGL_BLUE_SIZE, 8,
1919 EGL_ALPHA_SIZE, 8,
1920 EGL_DEPTH_SIZE, 0,
Romain Guy8efca542012-10-15 18:09:49 -07001921 EGL_CONFIG_CAVEAT, EGL_NONE,
Romain Guy735738c2012-12-03 12:34:51 -08001922 EGL_STENCIL_SIZE, stencilSize,
1923 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
Romain Guy484c7192011-07-25 11:56:33 -07001924 EGL_NONE
Romain Guye91a9c72011-05-02 14:53:30 -07001925 };
1926 }
Romain Guy735738c2012-12-03 12:34:51 -08001927
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001928 @Override
1929 void initCaches() {
Romain Guy3b748a42013-04-17 18:54:38 -07001930 if (GLES20Canvas.initCaches()) {
1931 // Caches were (re)initialized, rebind atlas
1932 initAtlas();
1933 }
1934 }
1935
1936 @Override
1937 void initAtlas() {
1938 IBinder binder = ServiceManager.getService("assetatlas");
Romain Guy927bc7d2013-05-03 11:32:09 -07001939 if (binder == null) return;
1940
Romain Guy3b748a42013-04-17 18:54:38 -07001941 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
1942 try {
Romain Guy80b12fc2013-05-29 15:54:25 -07001943 if (atlas.isCompatible(android.os.Process.myPpid())) {
1944 GraphicBuffer buffer = atlas.getBuffer();
1945 if (buffer != null) {
1946 int[] map = atlas.getMap();
1947 if (map != null) {
1948 GLES20Canvas.initAtlas(buffer, map);
1949 }
Romain Guy3b748a42013-04-17 18:54:38 -07001950 }
1951 }
1952 } catch (RemoteException e) {
1953 Log.w(LOG_TAG, "Could not acquire atlas", e);
1954 }
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001955 }
Romain Guye91a9c72011-05-02 14:53:30 -07001956
Romain Guyb8c0de22010-12-13 14:42:34 -08001957 @Override
1958 boolean canDraw() {
1959 return super.canDraw() && mGlCanvas != null;
1960 }
Romain Guye4d01122010-06-16 18:44:05 -07001961
1962 @Override
Chet Haase44b2fe32012-06-06 19:03:58 -07001963 int onPreDraw(Rect dirty) {
1964 return mGlCanvas.onPreDraw(dirty);
Romain Guye3924992010-06-10 18:51:21 -07001965 }
1966
Romain Guyb025b9c2010-09-16 14:16:48 -07001967 @Override
1968 void onPostDraw() {
1969 mGlCanvas.onPostDraw();
1970 }
1971
Romain Guyb051e892010-09-28 19:09:36 -07001972 @Override
Romain Guy98e4a522013-01-07 10:58:34 -08001973 void drawProfileData(View.AttachInfo attachInfo) {
Romain Guy48ef4a92013-01-10 18:38:46 -08001974 if (mDebugDataProvider != null) {
1975 final GraphDataProvider provider = mDebugDataProvider;
1976 initProfileDrawData(attachInfo, provider);
Romain Guy98e4a522013-01-07 10:58:34 -08001977
Romain Guy48ef4a92013-01-10 18:38:46 -08001978 final int height = provider.getVerticalUnitSize();
1979 final int margin = provider.getHorizontaUnitMargin();
1980 final int width = provider.getHorizontalUnitSize();
Romain Guy672433d2013-01-04 19:05:13 -08001981
1982 int x = 0;
1983 int count = 0;
1984 int current = 0;
1985
Romain Guy48ef4a92013-01-10 18:38:46 -08001986 final float[] data = provider.getData();
1987 final int elementCount = provider.getElementCount();
1988 final int graphType = provider.getGraphType();
1989
1990 int totalCount = provider.getFrameCount() * elementCount;
1991 if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
1992 totalCount -= elementCount;
1993 }
1994
1995 for (int i = 0; i < totalCount; i += elementCount) {
1996 if (data[i] < 0.0f) break;
Romain Guy672433d2013-01-04 19:05:13 -08001997
1998 int index = count * 4;
Romain Guy48ef4a92013-01-10 18:38:46 -08001999 if (i == provider.getCurrentFrame() * elementCount) current = index;
Romain Guy672433d2013-01-04 19:05:13 -08002000
Romain Guy98e4a522013-01-07 10:58:34 -08002001 x += margin;
2002 int x2 = x + width;
Romain Guy672433d2013-01-04 19:05:13 -08002003
2004 int y2 = mHeight;
Romain Guy48ef4a92013-01-10 18:38:46 -08002005 int y1 = (int) (y2 - data[i] * height);
Romain Guy672433d2013-01-04 19:05:13 -08002006
Romain Guy48ef4a92013-01-10 18:38:46 -08002007 switch (graphType) {
2008 case GraphDataProvider.GRAPH_TYPE_BARS: {
2009 for (int j = 0; j < elementCount; j++) {
2010 //noinspection MismatchedReadAndWriteOfArray
2011 final float[] r = mProfileShapes[j];
2012 r[index] = x;
2013 r[index + 1] = y1;
2014 r[index + 2] = x2;
2015 r[index + 3] = y2;
Romain Guy672433d2013-01-04 19:05:13 -08002016
Romain Guy48ef4a92013-01-10 18:38:46 -08002017 y2 = y1;
2018 if (j < elementCount - 1) {
2019 y1 = (int) (y2 - data[i + j + 1] * height);
2020 }
2021 }
2022 } break;
2023 case GraphDataProvider.GRAPH_TYPE_LINES: {
2024 for (int j = 0; j < elementCount; j++) {
2025 //noinspection MismatchedReadAndWriteOfArray
2026 final float[] r = mProfileShapes[j];
2027 r[index] = (x + x2) * 0.5f;
2028 r[index + 1] = index == 0 ? y1 : r[index - 1];
2029 r[index + 2] = r[index] + width;
2030 r[index + 3] = y1;
Romain Guy672433d2013-01-04 19:05:13 -08002031
Romain Guy48ef4a92013-01-10 18:38:46 -08002032 y2 = y1;
2033 if (j < elementCount - 1) {
2034 y1 = (int) (y2 - data[i + j + 1] * height);
2035 }
2036 }
2037 } break;
2038 }
Romain Guy672433d2013-01-04 19:05:13 -08002039
Romain Guy672433d2013-01-04 19:05:13 -08002040
Romain Guy98e4a522013-01-07 10:58:34 -08002041 x += width;
Romain Guy672433d2013-01-04 19:05:13 -08002042 count++;
2043 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002044
Romain Guy98e4a522013-01-07 10:58:34 -08002045 x += margin;
Romain Guy672433d2013-01-04 19:05:13 -08002046
Romain Guy48ef4a92013-01-10 18:38:46 -08002047 drawGraph(graphType, count);
2048 drawCurrentFrame(graphType, current);
2049 drawThreshold(x, height);
Romain Guy672433d2013-01-04 19:05:13 -08002050 }
2051 }
2052
Romain Guy48ef4a92013-01-10 18:38:46 -08002053 private void drawGraph(int graphType, int count) {
2054 for (int i = 0; i < mProfileShapes.length; i++) {
2055 mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
2056 switch (graphType) {
2057 case GraphDataProvider.GRAPH_TYPE_BARS:
Chris Craik2af46352012-11-26 18:30:17 -08002058 mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
Romain Guy48ef4a92013-01-10 18:38:46 -08002059 break;
2060 case GraphDataProvider.GRAPH_TYPE_LINES:
2061 mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
2062 break;
Romain Guy672433d2013-01-04 19:05:13 -08002063 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002064 }
2065 }
2066
2067 private void drawCurrentFrame(int graphType, int index) {
2068 if (index >= 0) {
2069 mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
2070 switch (graphType) {
2071 case GraphDataProvider.GRAPH_TYPE_BARS:
2072 mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
2073 mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
2074 mProfilePaint);
2075 break;
2076 case GraphDataProvider.GRAPH_TYPE_LINES:
2077 mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
2078 mProfileShapes[2][index], mHeight, mProfilePaint);
2079 break;
2080 }
2081 }
2082 }
2083
2084 private void drawThreshold(int x, int height) {
2085 float threshold = mDebugDataProvider.getThreshold();
2086 if (threshold > 0.0f) {
2087 mDebugDataProvider.setupThresholdPaint(mProfilePaint);
2088 int y = (int) (mHeight - threshold * height);
2089 mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
2090 }
2091 }
2092
2093 private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
2094 if (mProfileShapes == null) {
2095 final int elementCount = provider.getElementCount();
2096 final int frameCount = provider.getFrameCount();
2097
2098 mProfileShapes = new float[elementCount][];
2099 for (int i = 0; i < elementCount; i++) {
2100 mProfileShapes[i] = new float[frameCount * 4];
2101 }
2102
Romain Guy672433d2013-01-04 19:05:13 -08002103 mProfilePaint = new Paint();
2104 }
Romain Guy98e4a522013-01-07 10:58:34 -08002105
Romain Guy48ef4a92013-01-10 18:38:46 -08002106 mProfilePaint.reset();
2107 if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
2108 mProfilePaint.setAntiAlias(true);
2109 }
2110
Romain Guy98e4a522013-01-07 10:58:34 -08002111 if (mDisplayMetrics == null) {
2112 mDisplayMetrics = new DisplayMetrics();
2113 }
Romain Guy48ef4a92013-01-10 18:38:46 -08002114
Romain Guy98e4a522013-01-07 10:58:34 -08002115 attachInfo.mDisplay.getMetrics(mDisplayMetrics);
Romain Guy48ef4a92013-01-10 18:38:46 -08002116 provider.prepare(mDisplayMetrics);
Romain Guy672433d2013-01-04 19:05:13 -08002117 }
2118
2119 @Override
Romain Guy67f27952010-12-07 20:09:23 -08002120 void destroy(boolean full) {
Romain Guyb8c0de22010-12-13 14:42:34 -08002121 try {
2122 super.destroy(full);
2123 } finally {
2124 if (full && mGlCanvas != null) {
2125 mGlCanvas = null;
2126 }
Romain Guy67f27952010-12-07 20:09:23 -08002127 }
2128 }
2129
2130 @Override
Romain Guy11cb6422012-09-21 00:39:43 -07002131 void pushLayerUpdate(HardwareLayer layer) {
2132 mGlCanvas.pushLayerUpdate(layer);
2133 }
2134
2135 @Override
Romain Guy40543602013-06-12 15:31:28 -07002136 void flushLayerUpdates() {
2137 mGlCanvas.flushLayerUpdates();
2138 }
2139
2140 @Override
Romain Guy13631f32012-01-30 17:41:55 -08002141 public DisplayList createDisplayList(String name) {
2142 return new GLES20DisplayList(name);
Romain Guyb051e892010-09-28 19:09:36 -07002143 }
Romain Guyaa6c24c2011-04-28 18:40:04 -07002144
2145 @Override
Romain Guya9489272011-06-22 20:58:11 -07002146 HardwareLayer createHardwareLayer(boolean isOpaque) {
2147 return new GLES20TextureLayer(isOpaque);
Romain Guyaa6c24c2011-04-28 18:40:04 -07002148 }
2149
Romain Guy6c319ca2011-01-11 14:29:25 -08002150 @Override
Romain Guy52036b12013-02-14 18:03:37 -08002151 public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07002152 return new GLES20RenderLayer(width, height, isOpaque);
2153 }
2154
2155 @Override
Romain Guy78dd96d2013-05-03 14:24:16 -07002156 void countOverdraw(HardwareCanvas canvas) {
2157 ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
2158 }
2159
2160 @Override
2161 float getOverdraw(HardwareCanvas canvas) {
2162 return ((GLES20Canvas) canvas).getOverdraw();
2163 }
2164
2165 @Override
Romain Guy52036b12013-02-14 18:03:37 -08002166 public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07002167 return ((GLES20TextureLayer) layer).getSurfaceTexture();
2168 }
2169
Romain Guy6d7475d2011-07-27 16:28:21 -07002170 @Override
Jamie Gennis2af35242012-04-05 11:44:30 -07002171 void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
2172 ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
2173 }
2174
2175 @Override
Romain Guy1ac47652012-04-11 18:15:20 -07002176 boolean safelyRun(Runnable action) {
2177 boolean needsContext = true;
2178 if (isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) needsContext = false;
Romain Guy31f2c2e2011-11-21 10:55:41 -08002179
Romain Guy1ac47652012-04-11 18:15:20 -07002180 if (needsContext) {
2181 Gl20RendererEglContext managedContext =
2182 (Gl20RendererEglContext) sEglContextStorage.get();
2183 if (managedContext == null) return false;
2184 usePbufferSurface(managedContext.getContext());
2185 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002186
Romain Guy1ac47652012-04-11 18:15:20 -07002187 try {
2188 action.run();
2189 } finally {
Jesse Hall0872b372012-04-02 12:22:51 -07002190 if (needsContext) {
2191 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
2192 EGL_NO_SURFACE, EGL_NO_CONTEXT);
2193 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002194 }
Romain Guy1ac47652012-04-11 18:15:20 -07002195
2196 return true;
2197 }
2198
2199 @Override
Romain Guybd17bd32012-10-23 19:17:15 -07002200 void destroyLayers(final View view) {
2201 if (view != null) {
2202 safelyRun(new Runnable() {
2203 @Override
2204 public void run() {
2205 if (mCanvas != null) {
2206 mCanvas.clearLayerUpdates();
2207 }
2208 destroyHardwareLayer(view);
2209 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
2210 }
2211 });
2212 }
2213 }
2214
2215 private static void destroyHardwareLayer(View view) {
2216 view.destroyLayer(true);
2217
2218 if (view instanceof ViewGroup) {
2219 ViewGroup group = (ViewGroup) view;
2220
2221 int count = group.getChildCount();
2222 for (int i = 0; i < count; i++) {
2223 destroyHardwareLayer(group.getChildAt(i));
2224 }
2225 }
2226 }
2227
2228 @Override
Romain Guy1ac47652012-04-11 18:15:20 -07002229 void destroyHardwareResources(final View view) {
2230 if (view != null) {
2231 safelyRun(new Runnable() {
2232 @Override
2233 public void run() {
Chet Haase6a2d17f2012-09-30 12:14:13 -07002234 if (mCanvas != null) {
2235 mCanvas.clearLayerUpdates();
2236 }
Romain Guy1ac47652012-04-11 18:15:20 -07002237 destroyResources(view);
2238 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
2239 }
2240 });
2241 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08002242 }
Romain Guy244ada12012-03-28 16:41:26 -07002243
Romain Guy31f2c2e2011-11-21 10:55:41 -08002244 private static void destroyResources(View view) {
2245 view.destroyHardwareResources();
2246
2247 if (view instanceof ViewGroup) {
2248 ViewGroup group = (ViewGroup) view;
2249
2250 int count = group.getChildCount();
2251 for (int i = 0; i < count; i++) {
2252 destroyResources(group.getChildAt(i));
2253 }
2254 }
2255 }
Romain Guy6d7475d2011-07-27 16:28:21 -07002256
2257 static HardwareRenderer create(boolean translucent) {
2258 if (GLES20Canvas.isAvailable()) {
2259 return new Gl20Renderer(translucent);
2260 }
2261 return null;
2262 }
2263
Romain Guy19f86e82012-04-23 15:19:07 -07002264 static void startTrimMemory(int level) {
Romain Guy912a7b32011-07-26 18:57:28 -07002265 if (sEgl == null || sEglConfig == null) return;
2266
Romain Guy5d6999e2012-03-22 19:15:04 -07002267 Gl20RendererEglContext managedContext =
2268 (Gl20RendererEglContext) sEglContextStorage.get();
Romain Guy912a7b32011-07-26 18:57:28 -07002269 // We do not have OpenGL objects
Dianne Hackborn717a25d2011-11-15 18:59:59 -08002270 if (managedContext == null) {
Romain Guy912a7b32011-07-26 18:57:28 -07002271 return;
2272 } else {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08002273 usePbufferSurface(managedContext.getContext());
Romain Guye3924992010-06-10 18:51:21 -07002274 }
Romain Guy912a7b32011-07-26 18:57:28 -07002275
Dianne Hackborn27ff9132012-03-06 14:57:58 -08002276 if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
2277 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
2278 } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
2279 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
Romain Guybdf76092011-07-18 15:00:43 -07002280 }
Romain Guy19f86e82012-04-23 15:19:07 -07002281 }
Jesse Hall0872b372012-04-02 12:22:51 -07002282
Romain Guy19f86e82012-04-23 15:19:07 -07002283 static void endTrimMemory() {
2284 if (sEgl != null && sEglDisplay != null) {
2285 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
2286 }
Romain Guybdf76092011-07-18 15:00:43 -07002287 }
Romain Guy8ff6b9e2011-11-09 20:10:18 -08002288
2289 private static void usePbufferSurface(EGLContext eglContext) {
2290 synchronized (sPbufferLock) {
2291 // Create a temporary 1x1 pbuffer so we have a context
2292 // to clear our OpenGL objects
2293 if (sPbuffer == null) {
2294 sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
2295 EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
2296 });
2297 }
2298 }
2299 sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
2300 }
Romain Guye3924992010-06-10 18:51:21 -07002301 }
Romain Guy2d614592010-06-09 18:21:37 -07002302}