blob: 5b7a5af9a1cc1fd1d681baea1950e42158a3b758 [file] [log] [blame]
Romain Guy2d614592010-06-09 18:21:37 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
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
17
18package android.view;
19
Dianne Hackbornc68c9132011-07-29 01:25:18 -070020import android.content.ComponentCallbacks2;
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;
28import android.os.Looper;
Romain Guy02ccac62011-06-24 13:20:23 -070029import android.os.SystemClock;
30import android.os.SystemProperties;
Romain Guy77e67cf2012-06-19 16:38:50 -070031import android.os.Trace;
Romain Guye3924992010-06-10 18:51:21 -070032import android.util.Log;
Romain Guy8ff6b9e2011-11-09 20:10:18 -080033import com.google.android.gles_jni.EGLImpl;
Romain Guy2d614592010-06-09 18:21:37 -070034
35import javax.microedition.khronos.egl.EGL10;
36import javax.microedition.khronos.egl.EGL11;
37import javax.microedition.khronos.egl.EGLConfig;
38import javax.microedition.khronos.egl.EGLContext;
39import javax.microedition.khronos.egl.EGLDisplay;
40import javax.microedition.khronos.egl.EGLSurface;
Romain Guye3924992010-06-10 18:51:21 -070041import javax.microedition.khronos.opengles.GL;
Romain Guy2d614592010-06-09 18:21:37 -070042
Romain Guya9582652011-11-10 14:20:10 -080043import java.io.File;
Romain Guya676ad72012-02-13 17:47:10 -080044import java.io.PrintWriter;
Romain Guy77e67cf2012-06-19 16:38:50 -070045import java.util.concurrent.locks.ReentrantLock;
Romain Guya9582652011-11-10 14:20:10 -080046
Romain Guy484c7192011-07-25 11:56:33 -070047import static javax.microedition.khronos.egl.EGL10.*;
48
Romain Guy2d614592010-06-09 18:21:37 -070049/**
Joe Onoratoc6cc0f82011-04-12 11:53:13 -070050 * Interface for rendering a ViewAncestor using hardware acceleration.
Romain Guy2d614592010-06-09 18:21:37 -070051 *
52 * @hide
53 */
Romain Guy61c8c9c2010-08-09 20:48:09 -070054public abstract class HardwareRenderer {
Romain Guy4f6aff32011-01-12 16:21:41 -080055 static final String LOG_TAG = "HardwareRenderer";
Romain Guyfb8b7632010-08-23 21:05:08 -070056
Romain Guy52339202010-09-03 16:04:46 -070057 /**
Romain Guya9582652011-11-10 14:20:10 -080058 * Name of the file that holds the shaders cache.
59 */
60 private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
61
62 /**
Romain Guy7d7b5492011-01-24 16:33:45 -080063 * Turn on to only refresh the parts of the screen that need updating.
Romain Guy069ea0e2011-02-08 12:24:52 -080064 * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
65 * must also have the value "true".
Romain Guy7d7b5492011-01-24 16:33:45 -080066 */
67 public static final boolean RENDER_DIRTY_REGIONS = true;
68
69 /**
Romain Guy069ea0e2011-02-08 12:24:52 -080070 * System property used to enable or disable dirty regions invalidation.
71 * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
72 * The default value of this property is assumed to be true.
73 *
74 * Possible values:
75 * "true", to enable partial invalidates
76 * "false", to disable partial invalidates
77 */
Romain Guy4b8c4f82012-04-27 15:48:35 -070078 static final String RENDER_DIRTY_REGIONS_PROPERTY = "debug.hwui.render_dirty_regions";
Romain Guy9ace8f52011-07-07 20:50:11 -070079
80 /**
81 * System property used to enable or disable vsync.
82 * The default value of this property is assumed to be false.
83 *
84 * Possible values:
85 * "true", to disable vsync
86 * "false", to enable vsync
87 */
Romain Guy4b8c4f82012-04-27 15:48:35 -070088 static final String DISABLE_VSYNC_PROPERTY = "debug.hwui.disable_vsync";
Romain Guy069ea0e2011-02-08 12:24:52 -080089
90 /**
Romain Guya676ad72012-02-13 17:47:10 -080091 * System property used to enable or disable hardware rendering profiling.
92 * The default value of this property is assumed to be false.
Chet Haase09280602012-04-03 16:15:34 -070093 *
Romain Guya676ad72012-02-13 17:47:10 -080094 * When profiling is enabled, the adb shell dumpsys gfxinfo command will
95 * output extra information about the time taken to execute by the last
96 * frames.
97 *
98 * Possible values:
99 * "true", to enable profiling
100 * "false", to disable profiling
Romain Guy4b8c4f82012-04-27 15:48:35 -0700101 *
102 * @hide
Romain Guya676ad72012-02-13 17:47:10 -0800103 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700104 public static final String PROFILE_PROPERTY = "debug.hwui.profile";
Romain Guya676ad72012-02-13 17:47:10 -0800105
106 /**
Chet Haase09280602012-04-03 16:15:34 -0700107 * System property used to specify the number of frames to be used
108 * when doing hardware rendering profiling.
109 * The default value of this property is #PROFILE_MAX_FRAMES.
110 *
111 * When profiling is enabled, the adb shell dumpsys gfxinfo command will
112 * output extra information about the time taken to execute by the last
113 * frames.
114 *
115 * Possible values:
116 * "60", to set the limit of frames to 60
117 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700118 static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes";
Chet Haase09280602012-04-03 16:15:34 -0700119
120 /**
Romain Guy484c7192011-07-25 11:56:33 -0700121 * System property used to debug EGL configuration choice.
122 *
123 * Possible values:
Romain Guy484c7192011-07-25 11:56:33 -0700124 * "choice", print the chosen configuration only
125 * "all", print all possible configurations
126 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700127 static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config";
Romain Guy484c7192011-07-25 11:56:33 -0700128
129 /**
Romain Guy7d7b5492011-01-24 16:33:45 -0800130 * Turn on to draw dirty regions every other frame.
Romain Guyb04f7e92012-02-15 12:36:54 -0800131 *
132 * Possible values:
133 * "true", to enable dirty regions debugging
134 * "false", to disable dirty regions debugging
Romain Guy4b8c4f82012-04-27 15:48:35 -0700135 *
136 * @hide
Romain Guy7d7b5492011-01-24 16:33:45 -0800137 */
Romain Guy4b8c4f82012-04-27 15:48:35 -0700138 public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions";
Romain Guy4ff0cf42012-08-06 14:51:10 -0700139
140 /**
141 * Turn on to flash hardware layers when they update.
142 *
143 * Possible values:
144 * "true", to enable hardware layers updates debugging
145 * "false", to disable hardware layers updates debugging
146 *
147 * @hide
148 */
149 public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY =
150 "debug.hwui.show_layers_updates";
151
Romain Guy7d7b5492011-01-24 16:33:45 -0800152 /**
Romain Guy7c450aa2012-09-21 19:15:00 -0700153 * Turn on to show overdraw level.
154 *
155 * Possible values:
156 * "true", to enable overdraw debugging
157 * "false", to disable overdraw debugging
158 *
159 * @hide
160 */
161 public static final String DEBUG_SHOW_OVERDRAW_PROPERTY = "debug.hwui.show_overdraw";
162
163 /**
Romain Guy52339202010-09-03 16:04:46 -0700164 * A process can set this flag to false to prevent the use of hardware
165 * rendering.
166 *
167 * @hide
168 */
169 public static boolean sRendererDisabled = false;
170
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700171 /**
172 * Further hardware renderer disabling for the system process.
173 *
174 * @hide
175 */
176 public static boolean sSystemRendererDisabled = false;
177
Romain Guya676ad72012-02-13 17:47:10 -0800178 /**
179 * Number of frames to profile.
180 */
Romain Guya21f8772012-05-07 10:20:52 -0700181 private static final int PROFILE_MAX_FRAMES = 128;
Romain Guya676ad72012-02-13 17:47:10 -0800182
183 /**
184 * Number of floats per profiled frame.
185 */
186 private static final int PROFILE_FRAME_DATA_COUNT = 3;
187
Romain Guy2d614592010-06-09 18:21:37 -0700188 private boolean mEnabled;
189 private boolean mRequested = true;
190
191 /**
Romain Guy67f27952010-12-07 20:09:23 -0800192 * Invoke this method to disable hardware rendering in the current process.
Romain Guy52339202010-09-03 16:04:46 -0700193 *
194 * @hide
195 */
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700196 public static void disable(boolean system) {
Romain Guy52339202010-09-03 16:04:46 -0700197 sRendererDisabled = true;
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700198 if (system) {
199 sSystemRendererDisabled = true;
200 }
Romain Guy52339202010-09-03 16:04:46 -0700201 }
202
203 /**
Romain Guy61c8c9c2010-08-09 20:48:09 -0700204 * Indicates whether hardware acceleration is available under any form for
205 * the view hierarchy.
206 *
207 * @return True if the view hierarchy can potentially be hardware accelerated,
208 * false otherwise
209 */
210 public static boolean isAvailable() {
211 return GLES20Canvas.isAvailable();
212 }
213
214 /**
Romain Guy2d614592010-06-09 18:21:37 -0700215 * Destroys the hardware rendering context.
Romain Guy4caa4ed2010-08-25 14:46:24 -0700216 *
217 * @param full If true, destroys all associated resources.
Romain Guy2d614592010-06-09 18:21:37 -0700218 */
Romain Guy4caa4ed2010-08-25 14:46:24 -0700219 abstract void destroy(boolean full);
Romain Guy2d614592010-06-09 18:21:37 -0700220
221 /**
222 * Initializes the hardware renderer for the specified surface.
223 *
Romain Guy786fc932012-07-24 16:24:56 -0700224 * @param surface The surface to hardware accelerate
Romain Guy2d614592010-06-09 18:21:37 -0700225 *
226 * @return True if the initialization was successful, false otherwise.
227 */
Romain Guy786fc932012-07-24 16:24:56 -0700228 abstract boolean initialize(Surface surface) throws Surface.OutOfResourcesException;
Romain Guy2a83f002011-01-18 18:28:21 -0800229
230 /**
231 * Updates the hardware renderer for the specified surface.
Romain Guy786fc932012-07-24 16:24:56 -0700232 *
233 * @param surface The surface to hardware accelerate
Romain Guy2a83f002011-01-18 18:28:21 -0800234 */
Romain Guy786fc932012-07-24 16:24:56 -0700235 abstract void updateSurface(Surface surface) throws Surface.OutOfResourcesException;
Romain Guy2d614592010-06-09 18:21:37 -0700236
237 /**
Romain Guy31f2c2e2011-11-21 10:55:41 -0800238 * Destroys the layers used by the specified view hierarchy.
Romain Guy6d7475d2011-07-27 16:28:21 -0700239 *
240 * @param view The root of the view hierarchy
241 */
242 abstract void destroyLayers(View view);
243
244 /**
Romain Guy31f2c2e2011-11-21 10:55:41 -0800245 * Destroys all hardware rendering resources associated with the specified
246 * view hierarchy.
247 *
248 * @param view The root of the view hierarchy
249 */
250 abstract void destroyHardwareResources(View view);
251
252 /**
Romain Guy03985752011-07-11 15:33:51 -0700253 * This method should be invoked whenever the current hardware renderer
Romain Guycf15efb2011-08-02 12:59:32 -0700254 * context should be reset.
Romain Guy786fc932012-07-24 16:24:56 -0700255 *
256 * @param surface The surface to hardware accelerate
Romain Guy7e1160e2011-07-08 15:49:50 -0700257 */
Romain Guy786fc932012-07-24 16:24:56 -0700258 abstract void invalidate(Surface surface);
Romain Guy03985752011-07-11 15:33:51 -0700259
260 /**
261 * This method should be invoked to ensure the hardware renderer is in
262 * valid state (for instance, to ensure the correct EGL context is bound
263 * to the current thread.)
264 *
265 * @return true if the renderer is now valid, false otherwise
266 */
267 abstract boolean validate();
Romain Guy7e1160e2011-07-08 15:49:50 -0700268
269 /**
Romain Guy1ac47652012-04-11 18:15:20 -0700270 * This method ensures the hardware renderer is in a valid state
271 * before executing the specified action.
272 *
273 * This method will attempt to set a valid state even if the window
274 * the renderer is attached to was destroyed.
275 *
276 * @return true if the action was run
277 */
278 abstract boolean safelyRun(Runnable action);
279
280 /**
Romain Guy7e1160e2011-07-08 15:49:50 -0700281 * Setup the hardware renderer for drawing. This is called whenever the
282 * size of the target surface changes or when the surface is first created.
Romain Guy2d614592010-06-09 18:21:37 -0700283 *
284 * @param width Width of the drawing surface.
285 * @param height Height of the drawing surface.
Romain Guy2d614592010-06-09 18:21:37 -0700286 */
Romain Guyfb8b7632010-08-23 21:05:08 -0700287 abstract void setup(int width, int height);
Romain Guy2d614592010-06-09 18:21:37 -0700288
Romain Guy069ea0e2011-02-08 12:24:52 -0800289 /**
Chet Haase40e03832011-10-06 08:34:13 -0700290 * Gets the current width of the surface. This is the width that the surface
291 * was last set to in a call to {@link #setup(int, int)}.
292 *
293 * @return the current width of the surface
294 */
295 abstract int getWidth();
296
297 /**
298 * Gets the current height of the surface. This is the height that the surface
299 * was last set to in a call to {@link #setup(int, int)}.
300 *
301 * @return the current width of the surface
302 */
303 abstract int getHeight();
304
305 /**
Chet Haase08837c22011-11-28 11:53:21 -0800306 * Gets the current canvas associated with this HardwareRenderer.
307 *
308 * @return the current HardwareCanvas
309 */
310 abstract HardwareCanvas getCanvas();
311
312 /**
Romain Guya676ad72012-02-13 17:47:10 -0800313 * Outputs extra debugging information in the specified file descriptor.
314 * @param pw
315 */
316 abstract void dumpGfxInfo(PrintWriter pw);
Michael Jurkaa3fabff2012-03-28 17:22:29 +0200317
318 /**
319 * Outputs the total number of frames rendered (used for fps calculations)
320 *
321 * @return the number of frames rendered
322 */
323 abstract long getFrameCount();
324
Romain Guya676ad72012-02-13 17:47:10 -0800325 /**
Romain Guya9582652011-11-10 14:20:10 -0800326 * Sets the directory to use as a persistent storage for hardware rendering
327 * resources.
328 *
329 * @param cacheDir A directory the current process can write to
330 */
331 public static void setupDiskCache(File cacheDir) {
332 nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
333 }
334
335 private static native void nSetupShadersDiskCache(String cacheFile);
336
337 /**
Jamie Gennisb335fad2012-01-15 18:54:57 -0800338 * Notifies EGL that the frame is about to be rendered.
Romain Guy76878822012-03-30 14:54:22 -0700339 * @param size
Jamie Gennisb335fad2012-01-15 18:54:57 -0800340 */
Romain Guy76878822012-03-30 14:54:22 -0700341 private static void beginFrame(int[] size) {
342 nBeginFrame(size);
Jamie Gennisb335fad2012-01-15 18:54:57 -0800343 }
344
Romain Guy76878822012-03-30 14:54:22 -0700345 private static native void nBeginFrame(int[] size);
Jamie Gennisb335fad2012-01-15 18:54:57 -0800346
347 /**
Romain Guy244ada12012-03-28 16:41:26 -0700348 * Preserves the back buffer of the current surface after a buffer swap.
349 * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
350 * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
351 * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
352 *
353 * @return True if the swap behavior was successfully changed,
354 * false otherwise.
355 */
356 static boolean preserveBackBuffer() {
357 return nPreserveBackBuffer();
358 }
359
360 private static native boolean nPreserveBackBuffer();
361
362 /**
363 * Indicates whether the current surface preserves its back buffer
364 * after a buffer swap.
365 *
366 * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
367 * false otherwise
368 */
369 static boolean isBackBufferPreserved() {
370 return nIsBackBufferPreserved();
371 }
372
373 private static native boolean nIsBackBufferPreserved();
374
375 /**
376 * Disables v-sync. For performance testing only.
377 */
378 static void disableVsync() {
379 nDisableVsync();
380 }
381
382 private static native void nDisableVsync();
383
384 /**
Romain Guy11cb6422012-09-21 00:39:43 -0700385 * Indicates that the specified hardware layer needs to be updated
386 * as soon as possible.
387 *
388 * @param layer The hardware layer that needs an update
389 */
390 abstract void pushLayerUpdate(HardwareLayer layer);
391
392 /**
Romain Guy069ea0e2011-02-08 12:24:52 -0800393 * Interface used to receive callbacks whenever a view is drawn by
394 * a hardware renderer instance.
395 */
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800396 interface HardwareDrawCallbacks {
Romain Guy069ea0e2011-02-08 12:24:52 -0800397 /**
398 * Invoked before a view is drawn by a hardware renderer.
399 *
400 * @param canvas The Canvas used to render the view.
401 */
Romain Guy7d70fbf2011-05-24 17:40:25 -0700402 void onHardwarePreDraw(HardwareCanvas canvas);
Romain Guy069ea0e2011-02-08 12:24:52 -0800403
404 /**
405 * Invoked after a view is drawn by a hardware renderer.
406 *
407 * @param canvas The Canvas used to render the view.
408 */
Romain Guy7d70fbf2011-05-24 17:40:25 -0700409 void onHardwarePostDraw(HardwareCanvas canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800410 }
411
Romain Guy2d614592010-06-09 18:21:37 -0700412 /**
413 * Draws the specified view.
Romain Guy7d7b5492011-01-24 16:33:45 -0800414 *
Romain Guy2d614592010-06-09 18:21:37 -0700415 * @param view The view to draw.
416 * @param attachInfo AttachInfo tied to the specified view.
Romain Guy7d7b5492011-01-24 16:33:45 -0800417 * @param callbacks Callbacks invoked when drawing happens.
418 * @param dirty The dirty rectangle to update, can be null.
Romain Guy50d133e2011-08-12 15:25:28 -0700419 *
420 * @return true if the dirty rect was ignored, false otherwise
Romain Guy2d614592010-06-09 18:21:37 -0700421 */
Romain Guy50d133e2011-08-12 15:25:28 -0700422 abstract boolean draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Romain Guy7d7b5492011-01-24 16:33:45 -0800423 Rect dirty);
Romain Guy2d614592010-06-09 18:21:37 -0700424
425 /**
Romain Guy53ca03d2010-10-08 18:55:27 -0700426 * Creates a new display list that can be used to record batches of
427 * drawing operations.
Romain Guyb051e892010-09-28 19:09:36 -0700428 *
Romain Guy13631f32012-01-30 17:41:55 -0800429 * @param name The name of the display list, used for debugging purpose.
430 * May be null
431 *
Romain Guy53ca03d2010-10-08 18:55:27 -0700432 * @return A new display list.
Romain Guyb051e892010-09-28 19:09:36 -0700433 */
Romain Guy13631f32012-01-30 17:41:55 -0800434 public abstract DisplayList createDisplayList(String name);
Romain Guyb051e892010-09-28 19:09:36 -0700435
436 /**
Romain Guyaa6c24c2011-04-28 18:40:04 -0700437 * Creates a new hardware layer. A hardware layer built by calling this
438 * method will be treated as a texture layer, instead of as a render target.
439 *
Romain Guya9489272011-06-22 20:58:11 -0700440 * @param isOpaque Whether the layer should be opaque or not
441 *
Romain Guyaa6c24c2011-04-28 18:40:04 -0700442 * @return A hardware layer
Jamie Gennis2af35242012-04-05 11:44:30 -0700443 */
Romain Guya9489272011-06-22 20:58:11 -0700444 abstract HardwareLayer createHardwareLayer(boolean isOpaque);
Jamie Gennis2af35242012-04-05 11:44:30 -0700445
Romain Guyaa6c24c2011-04-28 18:40:04 -0700446 /**
Romain Guy6c319ca2011-01-11 14:29:25 -0800447 * Creates a new hardware layer.
448 *
449 * @param width The minimum width of the layer
450 * @param height The minimum height of the layer
451 * @param isOpaque Whether the layer should be opaque or not
452 *
453 * @return A hardware layer
454 */
455 abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700456
457 /**
458 * Creates a new {@link SurfaceTexture} that can be used to render into the
459 * specified hardware layer.
460 *
461 *
462 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
463 *
464 * @return A {@link SurfaceTexture}
465 */
Romain Guye5e0c502011-06-15 15:18:31 -0700466 abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700467
468 /**
Jamie Gennis2af35242012-04-05 11:44:30 -0700469 * Sets the {@link android.graphics.SurfaceTexture} that will be used to
470 * render into the specified hardware layer.
471 *
472 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
473 * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer
474 */
475 abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture);
476
477 /**
Romain Guyba6be8a2012-04-23 18:22:09 -0700478 * Detaches the specified functor from the current functor execution queue.
479 *
480 * @param functor The native functor to remove from the execution queue.
481 *
482 * @see HardwareCanvas#callDrawGLFunction(int)
483 * @see #attachFunctor(android.view.View.AttachInfo, int)
484 */
485 abstract void detachFunctor(int functor);
486
487 /**
488 * Schedules the specified functor in the functors execution queue.
489 *
490 * @param attachInfo AttachInfo tied to this renderer.
491 * @param functor The native functor to insert in the execution queue.
492 *
493 * @see HardwareCanvas#callDrawGLFunction(int)
Chris Craik41ee4652012-05-31 15:05:57 -0700494 * @see #detachFunctor(int)
495 *
496 * @return true if the functor was attached successfully
Romain Guyba6be8a2012-04-23 18:22:09 -0700497 */
Chris Craik41ee4652012-05-31 15:05:57 -0700498 abstract boolean attachFunctor(View.AttachInfo attachInfo, int functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700499
500 /**
Romain Guy2d614592010-06-09 18:21:37 -0700501 * Initializes the hardware renderer for the specified surface and setup the
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700502 * renderer for drawing, if needed. This is invoked when the ViewAncestor has
Romain Guy2d614592010-06-09 18:21:37 -0700503 * potentially lost the hardware renderer. The hardware renderer should be
504 * reinitialized and setup when the render {@link #isRequested()} and
505 * {@link #isEnabled()}.
Romain Guy44d79742012-01-13 12:12:09 -0800506 *
Romain Guy2d614592010-06-09 18:21:37 -0700507 * @param width The width of the drawing surface.
508 * @param height The height of the drawing surface.
Romain Guy786fc932012-07-24 16:24:56 -0700509 * @param surface The surface to hardware accelerate
Romain Guydfab3632012-10-03 14:53:25 -0700510 *
511 * @return true if the surface was initialized, false otherwise. Returning
512 * false might mean that the surface was already initialized.
Romain Guy2d614592010-06-09 18:21:37 -0700513 */
Romain Guydfab3632012-10-03 14:53:25 -0700514 boolean initializeIfNeeded(int width, int height, Surface surface)
Romain Guy44d79742012-01-13 12:12:09 -0800515 throws Surface.OutOfResourcesException {
Romain Guy2d614592010-06-09 18:21:37 -0700516 if (isRequested()) {
517 // We lost the gl context, so recreate it.
518 if (!isEnabled()) {
Romain Guy786fc932012-07-24 16:24:56 -0700519 if (initialize(surface)) {
Romain Guyfb8b7632010-08-23 21:05:08 -0700520 setup(width, height);
Romain Guydfab3632012-10-03 14:53:25 -0700521 return true;
Romain Guy2d614592010-06-09 18:21:37 -0700522 }
523 }
Romain Guydfab3632012-10-03 14:53:25 -0700524 }
525 return false;
Romain Guy2d614592010-06-09 18:21:37 -0700526 }
527
528 /**
529 * Creates a hardware renderer using OpenGL.
530 *
531 * @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 -0700532 * @param translucent True if the surface is translucent, false otherwise
Romain Guy2d614592010-06-09 18:21:37 -0700533 *
534 * @return A hardware renderer backed by OpenGL.
535 */
Romain Guye4d01122010-06-16 18:44:05 -0700536 static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
Romain Guy2d614592010-06-09 18:21:37 -0700537 switch (glVersion) {
Romain Guye3924992010-06-10 18:51:21 -0700538 case 2:
Romain Guy16393512010-08-08 00:14:31 -0700539 return Gl20Renderer.create(translucent);
Romain Guy2d614592010-06-09 18:21:37 -0700540 }
541 throw new IllegalArgumentException("Unknown GL version: " + glVersion);
542 }
543
544 /**
Romain Guybdf76092011-07-18 15:00:43 -0700545 * Invoke this method when the system is running out of memory. This
546 * method will attempt to recover as much memory as possible, based on
547 * the specified hint.
548 *
549 * @param level Hint about the amount of memory that should be trimmed,
550 * see {@link android.content.ComponentCallbacks}
551 */
552 static void trimMemory(int level) {
Romain Guy19f86e82012-04-23 15:19:07 -0700553 startTrimMemory(level);
554 endTrimMemory();
555 }
556
557 /**
558 * Starts the process of trimming memory. Usually this call will setup
559 * hardware rendering context and reclaim memory.Extra cleanup might
560 * be required by calling {@link #endTrimMemory()}.
561 *
562 * @param level Hint about the amount of memory that should be trimmed,
563 * see {@link android.content.ComponentCallbacks}
564 */
565 static void startTrimMemory(int level) {
566 Gl20Renderer.startTrimMemory(level);
567 }
568
569 /**
570 * Finishes the process of trimming memory. This method will usually
571 * cleanup special resources used by the memory trimming process.
572 */
573 static void endTrimMemory() {
574 Gl20Renderer.endTrimMemory();
Romain Guybdf76092011-07-18 15:00:43 -0700575 }
576
577 /**
Romain Guy2d614592010-06-09 18:21:37 -0700578 * Indicates whether hardware acceleration is currently enabled.
579 *
580 * @return True if hardware acceleration is in use, false otherwise.
581 */
582 boolean isEnabled() {
583 return mEnabled;
584 }
585
586 /**
587 * Indicates whether hardware acceleration is currently enabled.
588 *
589 * @param enabled True if the hardware renderer is in use, false otherwise.
590 */
591 void setEnabled(boolean enabled) {
592 mEnabled = enabled;
593 }
594
595 /**
596 * Indicates whether hardware acceleration is currently request but not
597 * necessarily enabled yet.
598 *
599 * @return True if requested, false otherwise.
600 */
601 boolean isRequested() {
602 return mRequested;
603 }
604
605 /**
Romain Guy9745fae2010-12-08 11:39:15 -0800606 * Indicates whether hardware acceleration is currently requested but not
Romain Guy2d614592010-06-09 18:21:37 -0700607 * necessarily enabled yet.
608 *
609 * @return True to request hardware acceleration, false otherwise.
610 */
611 void setRequested(boolean requested) {
612 mRequested = requested;
613 }
614
Romain Guy2d614592010-06-09 18:21:37 -0700615 @SuppressWarnings({"deprecation"})
Romain Guye3924992010-06-10 18:51:21 -0700616 static abstract class GlRenderer extends HardwareRenderer {
Romain Guy16260e72011-09-01 14:26:11 -0700617 static final int SURFACE_STATE_ERROR = 0;
618 static final int SURFACE_STATE_SUCCESS = 1;
619 static final int SURFACE_STATE_UPDATED = 2;
Romain Guy8f3b8e32012-03-27 16:33:45 -0700620
Chris Craik65924a32012-04-05 17:52:11 -0700621 static final int FUNCTOR_PROCESS_DELAY = 4;
Romain Guy8f3b8e32012-03-27 16:33:45 -0700622
Romain Guyfb8b7632010-08-23 21:05:08 -0700623 static EGL10 sEgl;
624 static EGLDisplay sEglDisplay;
625 static EGLConfig sEglConfig;
Romain Guy566b3ef2011-07-18 18:38:12 -0700626 static final Object[] sEglLock = new Object[0];
Chet Haase40e03832011-10-06 08:34:13 -0700627 int mWidth = -1, mHeight = -1;
Romain Guy2d614592010-06-09 18:21:37 -0700628
Romain Guy5d6999e2012-03-22 19:15:04 -0700629 static final ThreadLocal<ManagedEGLContext> sEglContextStorage
630 = new ThreadLocal<ManagedEGLContext>();
Romain Guy566b3ef2011-07-18 18:38:12 -0700631
632 EGLContext mEglContext;
633 Thread mEglThread;
Romain Guyfb8b7632010-08-23 21:05:08 -0700634
635 EGLSurface mEglSurface;
636
Romain Guye3924992010-06-10 18:51:21 -0700637 GL mGl;
Romain Guy67f27952010-12-07 20:09:23 -0800638 HardwareCanvas mCanvas;
Romain Guya676ad72012-02-13 17:47:10 -0800639
Michael Jurkaa3fabff2012-03-28 17:22:29 +0200640 long mFrameCount;
Romain Guy7d7b5492011-01-24 16:33:45 -0800641 Paint mDebugPaint;
642
Romain Guy7e1160e2011-07-08 15:49:50 -0700643 static boolean sDirtyRegions;
644 static final boolean sDirtyRegionsRequested;
645 static {
646 String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
647 //noinspection PointlessBooleanExpression,ConstantConditions
648 sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
649 sDirtyRegionsRequested = sDirtyRegions;
650 }
651
652 boolean mDirtyRegionsEnabled;
Romain Guy9477c6e2011-12-09 12:27:21 -0800653 boolean mUpdateDirtyRegions;
654
Romain Guy9ace8f52011-07-07 20:50:11 -0700655 final boolean mVsyncDisabled;
Romain Guye3924992010-06-10 18:51:21 -0700656
Romain Guya676ad72012-02-13 17:47:10 -0800657 final boolean mProfileEnabled;
658 final float[] mProfileData;
Romain Guy77e67cf2012-06-19 16:38:50 -0700659 final ReentrantLock mProfileLock;
Romain Guya676ad72012-02-13 17:47:10 -0800660 int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
Romain Guyb04f7e92012-02-15 12:36:54 -0800661
662 final boolean mDebugDirtyRegions;
Romain Guy7c450aa2012-09-21 19:15:00 -0700663 final boolean mShowOverdraw;
Romain Guya676ad72012-02-13 17:47:10 -0800664
Romain Guye4d01122010-06-16 18:44:05 -0700665 final int mGlVersion;
666 final boolean mTranslucent;
Romain Guye3924992010-06-10 18:51:21 -0700667
Romain Guyfb8b7632010-08-23 21:05:08 -0700668 private boolean mDestroyed;
Romain Guy566b3ef2011-07-18 18:38:12 -0700669
Romain Guycabfcc12011-03-07 18:06:46 -0800670 private final Rect mRedrawClip = new Rect();
Romain Guy8f3b8e32012-03-27 16:33:45 -0700671
Romain Guy76878822012-03-30 14:54:22 -0700672 private final int[] mSurfaceSize = new int[2];
Romain Guy8f3b8e32012-03-27 16:33:45 -0700673 private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
Romain Guyfb8b7632010-08-23 21:05:08 -0700674
Romain Guye4d01122010-06-16 18:44:05 -0700675 GlRenderer(int glVersion, boolean translucent) {
Romain Guye3924992010-06-10 18:51:21 -0700676 mGlVersion = glVersion;
Romain Guye4d01122010-06-16 18:44:05 -0700677 mTranslucent = translucent;
Romain Guyb04f7e92012-02-15 12:36:54 -0800678
679 String property;
Romain Guy9ace8f52011-07-07 20:50:11 -0700680
Romain Guyb04f7e92012-02-15 12:36:54 -0800681 property = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false");
682 mVsyncDisabled = "true".equalsIgnoreCase(property);
Romain Guy9ace8f52011-07-07 20:50:11 -0700683 if (mVsyncDisabled) {
684 Log.d(LOG_TAG, "Disabling v-sync");
685 }
Romain Guya676ad72012-02-13 17:47:10 -0800686
Romain Guy13b90732012-05-21 12:13:31 -0700687 property = SystemProperties.get(PROFILE_PROPERTY, "false");
688 mProfileEnabled = "true".equalsIgnoreCase(property);
689 if (mProfileEnabled) {
690 Log.d(LOG_TAG, "Profiling hardware renderer");
Romain Guya676ad72012-02-13 17:47:10 -0800691 }
692
693 if (mProfileEnabled) {
Chet Haase09280602012-04-03 16:15:34 -0700694 property = SystemProperties.get(PROFILE_MAXFRAMES_PROPERTY,
695 Integer.toString(PROFILE_MAX_FRAMES));
696 int maxProfileFrames = Integer.valueOf(property);
697 mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
698 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
699 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
700 }
Romain Guy77e67cf2012-06-19 16:38:50 -0700701
702 mProfileLock = new ReentrantLock();
Romain Guya676ad72012-02-13 17:47:10 -0800703 } else {
704 mProfileData = null;
Romain Guy77e67cf2012-06-19 16:38:50 -0700705 mProfileLock = null;
Romain Guya676ad72012-02-13 17:47:10 -0800706 }
Romain Guyb04f7e92012-02-15 12:36:54 -0800707
708 property = SystemProperties.get(DEBUG_DIRTY_REGIONS_PROPERTY, "false");
709 mDebugDirtyRegions = "true".equalsIgnoreCase(property);
710 if (mDebugDirtyRegions) {
711 Log.d(LOG_TAG, "Debugging dirty regions");
712 }
Romain Guy7c450aa2012-09-21 19:15:00 -0700713
714 mShowOverdraw = SystemProperties.getBoolean(
715 HardwareRenderer.DEBUG_SHOW_OVERDRAW_PROPERTY, false);
Romain Guya676ad72012-02-13 17:47:10 -0800716 }
717
718 @Override
719 void dumpGfxInfo(PrintWriter pw) {
720 if (mProfileEnabled) {
721 pw.printf("\n\tDraw\tProcess\tExecute\n");
Romain Guy77e67cf2012-06-19 16:38:50 -0700722
723 mProfileLock.lock();
724 try {
725 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
726 if (mProfileData[i] < 0) {
727 break;
728 }
729 pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
730 mProfileData[i + 2]);
731 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
Chet Haase09280602012-04-03 16:15:34 -0700732 }
Romain Guy77e67cf2012-06-19 16:38:50 -0700733 mProfileCurrentFrame = mProfileData.length;
734 } finally {
735 mProfileLock.unlock();
Romain Guya676ad72012-02-13 17:47:10 -0800736 }
737 }
Romain Guy2d614592010-06-09 18:21:37 -0700738 }
739
Michael Jurkaa3fabff2012-03-28 17:22:29 +0200740 @Override
741 long getFrameCount() {
742 return mFrameCount;
743 }
744
Romain Guye3924992010-06-10 18:51:21 -0700745 /**
Romain Guy02ccac62011-06-24 13:20:23 -0700746 * Indicates whether this renderer instance can track and update dirty regions.
747 */
748 boolean hasDirtyRegions() {
Romain Guy7e1160e2011-07-08 15:49:50 -0700749 return mDirtyRegionsEnabled;
Romain Guy02ccac62011-06-24 13:20:23 -0700750 }
751
752 /**
Romain Guy4caa4ed2010-08-25 14:46:24 -0700753 * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
Romain Guye3924992010-06-10 18:51:21 -0700754 * is invoked and the requested flag is turned off. The error code is
755 * also logged as a warning.
756 */
Romain Guyb025b9c2010-09-16 14:16:48 -0700757 void checkEglErrors() {
Romain Guy2d614592010-06-09 18:21:37 -0700758 if (isEnabled()) {
Romain Guy740ee652012-09-17 18:11:40 -0700759 checkEglErrorsForced();
760 }
761 }
762
763 private void checkEglErrorsForced() {
764 int error = sEgl.eglGetError();
765 if (error != EGL_SUCCESS) {
766 // something bad has happened revert to
767 // normal rendering.
768 Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
769 fallback(error != EGL11.EGL_CONTEXT_LOST);
Romain Guy2d614592010-06-09 18:21:37 -0700770 }
771 }
Romain Guy67f27952010-12-07 20:09:23 -0800772
Romain Guy9745fae2010-12-08 11:39:15 -0800773 private void fallback(boolean fallback) {
774 destroy(true);
775 if (fallback) {
776 // we'll try again if it was context lost
777 setRequested(false);
778 Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
779 + "Switching back to software rendering.");
780 }
781 }
782
Romain Guy2d614592010-06-09 18:21:37 -0700783 @Override
Romain Guy786fc932012-07-24 16:24:56 -0700784 boolean initialize(Surface surface) throws Surface.OutOfResourcesException {
Romain Guy2d614592010-06-09 18:21:37 -0700785 if (isRequested() && !isEnabled()) {
Romain Guye3924992010-06-10 18:51:21 -0700786 initializeEgl();
Romain Guy786fc932012-07-24 16:24:56 -0700787 mGl = createEglSurface(surface);
Romain Guyfb8b7632010-08-23 21:05:08 -0700788 mDestroyed = false;
Romain Guye3924992010-06-10 18:51:21 -0700789
790 if (mGl != null) {
Romain Guyfb8b7632010-08-23 21:05:08 -0700791 int err = sEgl.eglGetError();
Romain Guy484c7192011-07-25 11:56:33 -0700792 if (err != EGL_SUCCESS) {
Romain Guy4caa4ed2010-08-25 14:46:24 -0700793 destroy(true);
Romain Guye3924992010-06-10 18:51:21 -0700794 setRequested(false);
795 } else {
Romain Guy4caa4ed2010-08-25 14:46:24 -0700796 if (mCanvas == null) {
797 mCanvas = createCanvas();
Romain Guyfb8b7632010-08-23 21:05:08 -0700798 }
Romain Guye3924992010-06-10 18:51:21 -0700799 if (mCanvas != null) {
800 setEnabled(true);
801 } else {
802 Log.w(LOG_TAG, "Hardware accelerated Canvas could not be created");
803 }
804 }
805
806 return mCanvas != null;
807 }
Romain Guy2d614592010-06-09 18:21:37 -0700808 }
809 return false;
810 }
Romain Guy2a83f002011-01-18 18:28:21 -0800811
812 @Override
Romain Guy786fc932012-07-24 16:24:56 -0700813 void updateSurface(Surface surface) throws Surface.OutOfResourcesException {
Romain Guy2a83f002011-01-18 18:28:21 -0800814 if (isRequested() && isEnabled()) {
Romain Guy786fc932012-07-24 16:24:56 -0700815 createEglSurface(surface);
Romain Guy2a83f002011-01-18 18:28:21 -0800816 }
817 }
Romain Guy2d614592010-06-09 18:21:37 -0700818
Romain Guy5d6999e2012-03-22 19:15:04 -0700819 abstract HardwareCanvas createCanvas();
Romain Guye3924992010-06-10 18:51:21 -0700820
Romain Guy29d23ec2011-07-25 14:42:24 -0700821 abstract int[] getConfig(boolean dirtyRegions);
822
Romain Guye3924992010-06-10 18:51:21 -0700823 void initializeEgl() {
Romain Guy566b3ef2011-07-18 18:38:12 -0700824 synchronized (sEglLock) {
825 if (sEgl == null && sEglConfig == null) {
826 sEgl = (EGL10) EGLContext.getEGL();
827
828 // Get to the default display.
Romain Guy484c7192011-07-25 11:56:33 -0700829 sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
Romain Guy566b3ef2011-07-18 18:38:12 -0700830
Romain Guy484c7192011-07-25 11:56:33 -0700831 if (sEglDisplay == EGL_NO_DISPLAY) {
Romain Guy566b3ef2011-07-18 18:38:12 -0700832 throw new RuntimeException("eglGetDisplay failed "
Romain Guy407ec782011-08-24 17:06:58 -0700833 + GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guy566b3ef2011-07-18 18:38:12 -0700834 }
835
836 // We can now initialize EGL for that display
837 int[] version = new int[2];
838 if (!sEgl.eglInitialize(sEglDisplay, version)) {
839 throw new RuntimeException("eglInitialize failed " +
Romain Guy407ec782011-08-24 17:06:58 -0700840 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guy566b3ef2011-07-18 18:38:12 -0700841 }
Romain Guy740ee652012-09-17 18:11:40 -0700842
843 checkEglErrorsForced();
844
Romain Guye91a9c72011-05-02 14:53:30 -0700845 sEglConfig = chooseEglConfig();
Romain Guy069ea0e2011-02-08 12:24:52 -0800846 if (sEglConfig == null) {
Romain Guy566b3ef2011-07-18 18:38:12 -0700847 // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
848 if (sDirtyRegions) {
849 sDirtyRegions = false;
850 sEglConfig = chooseEglConfig();
851 if (sEglConfig == null) {
852 throw new RuntimeException("eglConfig not initialized");
853 }
854 } else {
855 throw new RuntimeException("eglConfig not initialized");
856 }
Romain Guy069ea0e2011-02-08 12:24:52 -0800857 }
Romain Guy069ea0e2011-02-08 12:24:52 -0800858 }
859 }
Romain Guy566b3ef2011-07-18 18:38:12 -0700860
Romain Guy5d6999e2012-03-22 19:15:04 -0700861 ManagedEGLContext managedContext = sEglContextStorage.get();
Dianne Hackborn717a25d2011-11-15 18:59:59 -0800862 mEglContext = managedContext != null ? managedContext.getContext() : null;
Romain Guy566b3ef2011-07-18 18:38:12 -0700863 mEglThread = Thread.currentThread();
864
865 if (mEglContext == null) {
866 mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
Romain Guy5d6999e2012-03-22 19:15:04 -0700867 sEglContextStorage.set(createManagedContext(mEglContext));
Romain Guy566b3ef2011-07-18 18:38:12 -0700868 }
Romain Guy2d614592010-06-09 18:21:37 -0700869 }
870
Romain Guy5d6999e2012-03-22 19:15:04 -0700871 abstract ManagedEGLContext createManagedContext(EGLContext eglContext);
872
Romain Guye91a9c72011-05-02 14:53:30 -0700873 private EGLConfig chooseEglConfig() {
Romain Guye91a9c72011-05-02 14:53:30 -0700874 EGLConfig[] configs = new EGLConfig[1];
Romain Guy484c7192011-07-25 11:56:33 -0700875 int[] configsCount = new int[1];
Romain Guy7e1160e2011-07-08 15:49:50 -0700876 int[] configSpec = getConfig(sDirtyRegions);
Romain Guy484c7192011-07-25 11:56:33 -0700877
878 // Debug
Romain Guy29d23ec2011-07-25 14:42:24 -0700879 final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
Romain Guy484c7192011-07-25 11:56:33 -0700880 if ("all".equalsIgnoreCase(debug)) {
881 sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
882
883 EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
884 sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
885 configsCount[0], configsCount);
886
887 for (EGLConfig config : debugConfigs) {
888 printConfig(config);
889 }
890 }
891
Romain Guye91a9c72011-05-02 14:53:30 -0700892 if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
893 throw new IllegalArgumentException("eglChooseConfig failed " +
Romain Guy407ec782011-08-24 17:06:58 -0700894 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guye91a9c72011-05-02 14:53:30 -0700895 } else if (configsCount[0] > 0) {
Romain Guy484c7192011-07-25 11:56:33 -0700896 if ("choice".equalsIgnoreCase(debug)) {
897 printConfig(configs[0]);
898 }
Romain Guye91a9c72011-05-02 14:53:30 -0700899 return configs[0];
900 }
Romain Guy484c7192011-07-25 11:56:33 -0700901
Romain Guye91a9c72011-05-02 14:53:30 -0700902 return null;
903 }
904
Romain Guye979e622012-03-20 13:50:27 -0700905 private static void printConfig(EGLConfig config) {
Romain Guy484c7192011-07-25 11:56:33 -0700906 int[] value = new int[1];
907
908 Log.d(LOG_TAG, "EGL configuration " + config + ":");
909
910 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
911 Log.d(LOG_TAG, " RED_SIZE = " + value[0]);
912
913 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
914 Log.d(LOG_TAG, " GREEN_SIZE = " + value[0]);
915
916 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
917 Log.d(LOG_TAG, " BLUE_SIZE = " + value[0]);
918
919 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
920 Log.d(LOG_TAG, " ALPHA_SIZE = " + value[0]);
921
922 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
923 Log.d(LOG_TAG, " DEPTH_SIZE = " + value[0]);
924
925 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
926 Log.d(LOG_TAG, " STENCIL_SIZE = " + value[0]);
927
Romain Guy8efca542012-10-15 18:09:49 -0700928 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value);
929 Log.d(LOG_TAG, " SAMPLE_BUFFERS = " + value[0]);
930
931 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value);
932 Log.d(LOG_TAG, " SAMPLES = " + value[0]);
933
Romain Guy484c7192011-07-25 11:56:33 -0700934 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
Romain Guy29d23ec2011-07-25 14:42:24 -0700935 Log.d(LOG_TAG, " SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
Romain Guy8efca542012-10-15 18:09:49 -0700936
937 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value);
938 Log.d(LOG_TAG, " CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
Romain Guy484c7192011-07-25 11:56:33 -0700939 }
940
Romain Guy786fc932012-07-24 16:24:56 -0700941 GL createEglSurface(Surface surface) throws Surface.OutOfResourcesException {
Romain Guye3924992010-06-10 18:51:21 -0700942 // Check preconditions.
Romain Guyfb8b7632010-08-23 21:05:08 -0700943 if (sEgl == null) {
Romain Guye3924992010-06-10 18:51:21 -0700944 throw new RuntimeException("egl not initialized");
Romain Guy2d614592010-06-09 18:21:37 -0700945 }
Romain Guyfb8b7632010-08-23 21:05:08 -0700946 if (sEglDisplay == null) {
Romain Guye3924992010-06-10 18:51:21 -0700947 throw new RuntimeException("eglDisplay not initialized");
948 }
Romain Guyfb8b7632010-08-23 21:05:08 -0700949 if (sEglConfig == null) {
Romain Guy069ea0e2011-02-08 12:24:52 -0800950 throw new RuntimeException("eglConfig not initialized");
Romain Guye3924992010-06-10 18:51:21 -0700951 }
Romain Guy566b3ef2011-07-18 18:38:12 -0700952 if (Thread.currentThread() != mEglThread) {
Romain Guyfb8b7632010-08-23 21:05:08 -0700953 throw new IllegalStateException("HardwareRenderer cannot be used "
954 + "from multiple threads");
955 }
Romain Guye3924992010-06-10 18:51:21 -0700956
Romain Guy6d7475d2011-07-27 16:28:21 -0700957 // In case we need to destroy an existing surface
958 destroySurface();
Romain Guye3924992010-06-10 18:51:21 -0700959
960 // Create an EGL surface we can render into.
Romain Guy786fc932012-07-24 16:24:56 -0700961 if (!createSurface(surface)) {
Romain Guy1d0c7082011-08-03 16:22:24 -0700962 return null;
Romain Guye3924992010-06-10 18:51:21 -0700963 }
964
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800965 initCaches();
Romain Guy6f7d9392011-06-02 14:17:28 -0700966
Romain Guy9477c6e2011-12-09 12:27:21 -0800967 return mEglContext.getGL();
968 }
969
970 private void enableDirtyRegions() {
Romain Guy6f7d9392011-06-02 14:17:28 -0700971 // If mDirtyRegions is set, this means we have an EGL configuration
972 // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
Romain Guy7e1160e2011-07-08 15:49:50 -0700973 if (sDirtyRegions) {
Romain Guy244ada12012-03-28 16:41:26 -0700974 if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
Romain Guy7d7b5492011-01-24 16:33:45 -0800975 Log.w(LOG_TAG, "Backbuffer cannot be preserved");
976 }
Romain Guy7e1160e2011-07-08 15:49:50 -0700977 } else if (sDirtyRegionsRequested) {
Romain Guy6f7d9392011-06-02 14:17:28 -0700978 // If mDirtyRegions is not set, our EGL configuration does not
979 // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
980 // swap behavior might be EGL_BUFFER_PRESERVED, which means we
981 // want to set mDirtyRegions. We try to do this only if dirty
982 // regions were initially requested as part of the device
983 // configuration (see RENDER_DIRTY_REGIONS)
Romain Guy244ada12012-03-28 16:41:26 -0700984 mDirtyRegionsEnabled = isBackBufferPreserved();
Romain Guy7d7b5492011-01-24 16:33:45 -0800985 }
Romain Guye3924992010-06-10 18:51:21 -0700986 }
987
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800988 abstract void initCaches();
989
Romain Guye3924992010-06-10 18:51:21 -0700990 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
Romain Guybd431522012-09-26 13:31:25 -0700991 int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
Romain Guye3924992010-06-10 18:51:21 -0700992
Romain Guyc0029362012-09-24 20:18:13 -0700993 EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
994 mGlVersion != 0 ? attribs : null);
Romain Guyed1b6f42012-09-24 21:42:18 -0700995 if (context == null || context == EGL_NO_CONTEXT) {
Romain Guyc0029362012-09-24 20:18:13 -0700996 //noinspection ConstantConditions
997 throw new IllegalStateException(
998 "Could not create an EGL context. eglCreateContext failed with error: " +
999 GLUtils.getEGLErrorString(sEgl.eglGetError()));
1000 }
1001 return context;
Romain Guy2d614592010-06-09 18:21:37 -07001002 }
1003
1004 @Override
Romain Guy4caa4ed2010-08-25 14:46:24 -07001005 void destroy(boolean full) {
1006 if (full && mCanvas != null) {
Romain Guy4caa4ed2010-08-25 14:46:24 -07001007 mCanvas = null;
1008 }
Romain Guye3924992010-06-10 18:51:21 -07001009
Romain Guy357c9422011-08-02 11:32:49 -07001010 if (!isEnabled() || mDestroyed) {
1011 setEnabled(false);
1012 return;
1013 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001014
Romain Guy6d7475d2011-07-27 16:28:21 -07001015 destroySurface();
Romain Guye3924992010-06-10 18:51:21 -07001016 setEnabled(false);
Romain Guy357c9422011-08-02 11:32:49 -07001017
1018 mDestroyed = true;
1019 mGl = null;
Romain Guyfb8b7632010-08-23 21:05:08 -07001020 }
1021
Romain Guy6d7475d2011-07-27 16:28:21 -07001022 void destroySurface() {
1023 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
1024 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1025 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
1026 mEglSurface = null;
1027 }
1028 }
1029
Romain Guye3924992010-06-10 18:51:21 -07001030 @Override
Romain Guy786fc932012-07-24 16:24:56 -07001031 void invalidate(Surface surface) {
Romain Guy7e1160e2011-07-08 15:49:50 -07001032 // Cancels any existing buffer to ensure we'll get a buffer
1033 // of the right size before we call eglSwapBuffers
Romain Guycf15efb2011-08-02 12:59:32 -07001034 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
Romain Guy1d0c7082011-08-03 16:22:24 -07001035
Romain Guyd3facf32011-08-03 11:14:38 -07001036 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
1037 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
Romain Guy1d0c7082011-08-03 16:22:24 -07001038 mEglSurface = null;
1039 setEnabled(false);
Romain Guyd3facf32011-08-03 11:14:38 -07001040 }
Romain Guycf15efb2011-08-02 12:59:32 -07001041
Romain Guy786fc932012-07-24 16:24:56 -07001042 if (surface.isValid()) {
1043 if (!createSurface(surface)) {
Romain Guy1d0c7082011-08-03 16:22:24 -07001044 return;
Romain Guycf15efb2011-08-02 12:59:32 -07001045 }
Romain Guy9477c6e2011-12-09 12:27:21 -08001046
1047 mUpdateDirtyRegions = true;
1048
Romain Guy86e3e222011-08-16 14:30:08 -07001049 if (mCanvas != null) {
1050 setEnabled(true);
1051 }
Romain Guycf15efb2011-08-02 12:59:32 -07001052 }
Romain Guy03985752011-07-11 15:33:51 -07001053 }
Romain Guycf15efb2011-08-02 12:59:32 -07001054
Romain Guy786fc932012-07-24 16:24:56 -07001055 private boolean createSurface(Surface surface) {
1056 mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
Romain Guy1d0c7082011-08-03 16:22:24 -07001057
1058 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
1059 int error = sEgl.eglGetError();
1060 if (error == EGL_BAD_NATIVE_WINDOW) {
1061 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
1062 return false;
1063 }
1064 throw new RuntimeException("createWindowSurface failed "
Romain Guy407ec782011-08-24 17:06:58 -07001065 + GLUtils.getEGLErrorString(error));
Romain Guy1d0c7082011-08-03 16:22:24 -07001066 }
Romain Guybd431522012-09-26 13:31:25 -07001067
1068 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
1069 throw new IllegalStateException("eglMakeCurrent failed " +
1070 GLUtils.getEGLErrorString(sEgl.eglGetError()));
1071 }
1072
1073 enableDirtyRegions();
1074
Romain Guy1d0c7082011-08-03 16:22:24 -07001075 return true;
1076 }
1077
Romain Guy03985752011-07-11 15:33:51 -07001078 @Override
1079 boolean validate() {
1080 return checkCurrent() != SURFACE_STATE_ERROR;
Romain Guy7e1160e2011-07-08 15:49:50 -07001081 }
1082
1083 @Override
Romain Guyfb8b7632010-08-23 21:05:08 -07001084 void setup(int width, int height) {
Romain Guyeca9b1f2011-08-26 13:36:37 -07001085 if (validate()) {
1086 mCanvas.setViewport(width, height);
Chet Haase40e03832011-10-06 08:34:13 -07001087 mWidth = width;
1088 mHeight = height;
Romain Guyeca9b1f2011-08-26 13:36:37 -07001089 }
Romain Guye3924992010-06-10 18:51:21 -07001090 }
Romain Guy7d7b5492011-01-24 16:33:45 -08001091
Chet Haase40e03832011-10-06 08:34:13 -07001092 @Override
1093 int getWidth() {
1094 return mWidth;
1095 }
1096
1097 @Override
1098 int getHeight() {
1099 return mHeight;
1100 }
1101
Chet Haase08837c22011-11-28 11:53:21 -08001102 @Override
1103 HardwareCanvas getCanvas() {
1104 return mCanvas;
1105 }
1106
Romain Guye3924992010-06-10 18:51:21 -07001107 boolean canDraw() {
1108 return mGl != null && mCanvas != null;
1109 }
1110
Chet Haase44b2fe32012-06-06 19:03:58 -07001111 int onPreDraw(Rect dirty) {
1112 return DisplayList.STATUS_DONE;
Romain Guye3924992010-06-10 18:51:21 -07001113 }
1114
Romain Guyb025b9c2010-09-16 14:16:48 -07001115 void onPostDraw() {
1116 }
Romain Guye3924992010-06-10 18:51:21 -07001117
Romain Guy8f3b8e32012-03-27 16:33:45 -07001118 class FunctorsRunnable implements Runnable {
1119 View.AttachInfo attachInfo;
1120
1121 @Override
1122 public void run() {
1123 final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
1124 if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
1125 return;
1126 }
1127
1128 final int surfaceState = checkCurrent();
1129 if (surfaceState != SURFACE_STATE_ERROR) {
1130 int status = mCanvas.invokeFunctors(mRedrawClip);
1131 handleFunctorStatus(attachInfo, status);
1132 }
1133 }
1134 }
1135
Romain Guye3924992010-06-10 18:51:21 -07001136 @Override
Romain Guy50d133e2011-08-12 15:25:28 -07001137 boolean draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Romain Guy7d7b5492011-01-24 16:33:45 -08001138 Rect dirty) {
Romain Guye3924992010-06-10 18:51:21 -07001139 if (canDraw()) {
Romain Guy02ccac62011-06-24 13:20:23 -07001140 if (!hasDirtyRegions()) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001141 dirty = null;
1142 }
Romain Guye3924992010-06-10 18:51:21 -07001143 attachInfo.mIgnoreDirtyState = true;
Romain Guy02ccac62011-06-24 13:20:23 -07001144 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
1145
Dianne Hackborn4702a852012-08-17 15:18:29 -07001146 view.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy03985752011-07-11 15:33:51 -07001147
Romain Guyd88f54c2011-01-24 20:22:49 -08001148 final int surfaceState = checkCurrent();
1149 if (surfaceState != SURFACE_STATE_ERROR) {
Romain Guy76878822012-03-30 14:54:22 -07001150 HardwareCanvas canvas = mCanvas;
1151 attachInfo.mHardwareCanvas = canvas;
Romain Guy77e67cf2012-06-19 16:38:50 -07001152
1153 if (mProfileEnabled) {
1154 mProfileLock.lock();
1155 }
1156
Romain Guyd88f54c2011-01-24 20:22:49 -08001157 // We had to change the current surface and/or context, redraw everything
1158 if (surfaceState == SURFACE_STATE_UPDATED) {
1159 dirty = null;
Romain Guy76878822012-03-30 14:54:22 -07001160 beginFrame(null);
1161 } else {
1162 int[] size = mSurfaceSize;
1163 beginFrame(size);
1164
1165 if (size[1] != mHeight || size[0] != mWidth) {
1166 mWidth = size[0];
1167 mHeight = size[1];
1168
1169 canvas.setViewport(mWidth, mHeight);
1170
1171 dirty = null;
1172 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001173 }
1174
Romain Guy2b7028e2012-09-19 17:25:38 -07001175 int saveCount = 0;
1176 int status = DisplayList.STATUS_DONE;
Chet Haasedaf98e92011-01-10 14:10:36 -08001177
Romain Guyb8c0de22010-12-13 14:42:34 -08001178 try {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001179 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
1180 == View.PFLAG_INVALIDATED;
1181 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
Romain Guy7d7b5492011-01-24 16:33:45 -08001182
Romain Guya676ad72012-02-13 17:47:10 -08001183 long getDisplayListStartTime = 0;
1184 if (mProfileEnabled) {
1185 mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
1186 if (mProfileCurrentFrame >= mProfileData.length) {
1187 mProfileCurrentFrame = 0;
1188 }
1189
Jeff Brown95db2b22011-11-30 19:54:41 -08001190 getDisplayListStartTime = System.nanoTime();
1191 }
1192
Romain Guy11cb6422012-09-21 00:39:43 -07001193 canvas.clearLayerUpdates();
Romain Guy77e67cf2012-06-19 16:38:50 -07001194
Romain Guy11cb6422012-09-21 00:39:43 -07001195 DisplayList displayList;
Romain Guy77e67cf2012-06-19 16:38:50 -07001196 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
1197 try {
1198 displayList = view.getDisplayList();
1199 } finally {
1200 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1201 }
Jeff Brown95db2b22011-11-30 19:54:41 -08001202
Romain Guy7c25aab2012-10-18 15:05:02 -07001203 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
1204 try {
1205 status = onPreDraw(dirty);
1206 } finally {
1207 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1208 }
Romain Guy2b7028e2012-09-19 17:25:38 -07001209 saveCount = canvas.save();
1210 callbacks.onHardwarePreDraw(canvas);
1211
Romain Guya676ad72012-02-13 17:47:10 -08001212 if (mProfileEnabled) {
Jeff Brown95db2b22011-11-30 19:54:41 -08001213 long now = System.nanoTime();
Romain Guya676ad72012-02-13 17:47:10 -08001214 float total = (now - getDisplayListStartTime) * 0.000001f;
1215 //noinspection PointlessArithmeticExpression
1216 mProfileData[mProfileCurrentFrame] = total;
Jeff Brown95db2b22011-11-30 19:54:41 -08001217 }
1218
Chet Haasedaf98e92011-01-10 14:10:36 -08001219 if (displayList != null) {
Romain Guya676ad72012-02-13 17:47:10 -08001220 long drawDisplayListStartTime = 0;
1221 if (mProfileEnabled) {
Jeff Brown95db2b22011-11-30 19:54:41 -08001222 drawDisplayListStartTime = System.nanoTime();
1223 }
1224
Romain Guy77e67cf2012-06-19 16:38:50 -07001225 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
1226 try {
1227 status |= canvas.drawDisplayList(displayList, mRedrawClip,
1228 DisplayList.FLAG_CLIP_CHILDREN);
1229 } finally {
1230 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1231 }
Jeff Brown95db2b22011-11-30 19:54:41 -08001232
Romain Guya676ad72012-02-13 17:47:10 -08001233 if (mProfileEnabled) {
Jeff Brown95db2b22011-11-30 19:54:41 -08001234 long now = System.nanoTime();
Romain Guya676ad72012-02-13 17:47:10 -08001235 float total = (now - drawDisplayListStartTime) * 0.000001f;
1236 mProfileData[mProfileCurrentFrame + 1] = total;
Jeff Brown95db2b22011-11-30 19:54:41 -08001237 }
1238
Romain Guy8f3b8e32012-03-27 16:33:45 -07001239 handleFunctorStatus(attachInfo, status);
Chet Haasedaf98e92011-01-10 14:10:36 -08001240 } else {
1241 // Shouldn't reach here
1242 view.draw(canvas);
1243 }
Romain Guyb04f7e92012-02-15 12:36:54 -08001244 } finally {
1245 callbacks.onHardwarePostDraw(canvas);
1246 canvas.restoreToCount(saveCount);
1247 view.mRecreateDisplayList = false;
Romain Guy19f86e82012-04-23 15:19:07 -07001248
Michael Jurkaa3fabff2012-03-28 17:22:29 +02001249 mFrameCount++;
Romain Guy19f86e82012-04-23 15:19:07 -07001250
Romain Guyb04f7e92012-02-15 12:36:54 -08001251 if (mDebugDirtyRegions) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001252 if (mDebugPaint == null) {
1253 mDebugPaint = new Paint();
1254 mDebugPaint.setColor(0x7fff0000);
1255 }
Romain Guy19f86e82012-04-23 15:19:07 -07001256
Michael Jurkaa3fabff2012-03-28 17:22:29 +02001257 if (dirty != null && (mFrameCount & 1) == 0) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001258 canvas.drawRect(dirty, mDebugPaint);
1259 }
1260 }
Romain Guyb8c0de22010-12-13 14:42:34 -08001261 }
Chet Haasedaf98e92011-01-10 14:10:36 -08001262
Romain Guyb8c0de22010-12-13 14:42:34 -08001263 onPostDraw();
Chet Haasedaf98e92011-01-10 14:10:36 -08001264
Romain Guyb8c0de22010-12-13 14:42:34 -08001265 attachInfo.mIgnoreDirtyState = false;
Chet Haase48659092012-05-31 15:21:51 -07001266
1267 if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
Chet Haase48659092012-05-31 15:21:51 -07001268 long eglSwapBuffersStartTime = 0;
1269 if (mProfileEnabled) {
1270 eglSwapBuffersStartTime = System.nanoTime();
1271 }
1272
1273 sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
1274
1275 if (mProfileEnabled) {
1276 long now = System.nanoTime();
1277 float total = (now - eglSwapBuffersStartTime) * 0.000001f;
1278 mProfileData[mProfileCurrentFrame + 2] = total;
1279 }
1280
1281 checkEglErrors();
Jeff Brown95db2b22011-11-30 19:54:41 -08001282 }
1283
Romain Guy77e67cf2012-06-19 16:38:50 -07001284 if (mProfileEnabled) {
1285 mProfileLock.unlock();
1286 }
1287
Romain Guy50d133e2011-08-12 15:25:28 -07001288 return dirty == null;
Romain Guye3924992010-06-10 18:51:21 -07001289 }
Romain Guye3924992010-06-10 18:51:21 -07001290 }
Romain Guy50d133e2011-08-12 15:25:28 -07001291
1292 return false;
Romain Guye3924992010-06-10 18:51:21 -07001293 }
Romain Guy03985752011-07-11 15:33:51 -07001294
Romain Guy8f3b8e32012-03-27 16:33:45 -07001295 private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
1296 // If the draw flag is set, functors will be invoked while executing
1297 // the tree of display lists
1298 if ((status & DisplayList.STATUS_DRAW) != 0) {
1299 if (mRedrawClip.isEmpty()) {
1300 attachInfo.mViewRootImpl.invalidate();
1301 } else {
1302 attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
1303 mRedrawClip.setEmpty();
1304 }
1305 }
1306
Chris Craik9efa2222012-12-04 15:15:31 -08001307 if ((status & DisplayList.STATUS_INVOKE) != 0 ||
1308 attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
1309 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
1310 mFunctorsRunnable.attachInfo = attachInfo;
1311 attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
Romain Guy8f3b8e32012-03-27 16:33:45 -07001312 }
1313 }
1314
Romain Guyba6be8a2012-04-23 18:22:09 -07001315 @Override
1316 void detachFunctor(int functor) {
1317 if (mCanvas != null) {
1318 mCanvas.detachFunctor(functor);
Chris Craik932b7f62012-06-06 13:59:33 -07001319 }
Romain Guyba6be8a2012-04-23 18:22:09 -07001320 }
1321
1322 @Override
Chris Craik41ee4652012-05-31 15:05:57 -07001323 boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
Romain Guyba6be8a2012-04-23 18:22:09 -07001324 if (mCanvas != null) {
1325 mCanvas.attachFunctor(functor);
Chris Craik9efa2222012-12-04 15:15:31 -08001326 mFunctorsRunnable.attachInfo = attachInfo;
1327 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
1328 attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0);
Chris Craik41ee4652012-05-31 15:05:57 -07001329 return true;
Romain Guyba6be8a2012-04-23 18:22:09 -07001330 }
Chris Craik41ee4652012-05-31 15:05:57 -07001331 return false;
Romain Guyba6be8a2012-04-23 18:22:09 -07001332 }
1333
Romain Guy03985752011-07-11 15:33:51 -07001334 /**
Romain Guy566b3ef2011-07-18 18:38:12 -07001335 * Ensures the current EGL context is the one we expect.
Romain Guy03985752011-07-11 15:33:51 -07001336 *
1337 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
1338 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
1339 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
1340 */
Romain Guy912a7b32011-07-26 18:57:28 -07001341 int checkCurrent() {
Romain Guy566b3ef2011-07-18 18:38:12 -07001342 if (mEglThread != Thread.currentThread()) {
Romain Guy03985752011-07-11 15:33:51 -07001343 throw new IllegalStateException("Hardware acceleration can only be used with a " +
Romain Guy566b3ef2011-07-18 18:38:12 -07001344 "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
Romain Guy03985752011-07-11 15:33:51 -07001345 "Current thread: " + Thread.currentThread());
1346 }
1347
Romain Guy566b3ef2011-07-18 18:38:12 -07001348 if (!mEglContext.equals(sEgl.eglGetCurrentContext()) ||
Romain Guy484c7192011-07-25 11:56:33 -07001349 !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
Romain Guy566b3ef2011-07-18 18:38:12 -07001350 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
Romain Guy9745fae2010-12-08 11:39:15 -08001351 Log.e(LOG_TAG, "eglMakeCurrent failed " +
Romain Guy407ec782011-08-24 17:06:58 -07001352 GLUtils.getEGLErrorString(sEgl.eglGetError()));
Romain Guyeca9b1f2011-08-26 13:36:37 -07001353 fallback(true);
Romain Guyd88f54c2011-01-24 20:22:49 -08001354 return SURFACE_STATE_ERROR;
1355 } else {
Romain Guy9477c6e2011-12-09 12:27:21 -08001356 if (mUpdateDirtyRegions) {
1357 enableDirtyRegions();
1358 mUpdateDirtyRegions = false;
1359 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001360 return SURFACE_STATE_UPDATED;
Romain Guyfb8b7632010-08-23 21:05:08 -07001361 }
1362 }
Romain Guyd88f54c2011-01-24 20:22:49 -08001363 return SURFACE_STATE_SUCCESS;
Romain Guyfb8b7632010-08-23 21:05:08 -07001364 }
Romain Guye3924992010-06-10 18:51:21 -07001365 }
Romain Guyfb8b7632010-08-23 21:05:08 -07001366
Romain Guye3924992010-06-10 18:51:21 -07001367 /**
1368 * Hardware renderer using OpenGL ES 2.0.
1369 */
1370 static class Gl20Renderer extends GlRenderer {
Romain Guye4d01122010-06-16 18:44:05 -07001371 private GLES20Canvas mGlCanvas;
1372
Romain Guy912a7b32011-07-26 18:57:28 -07001373 private static EGLSurface sPbuffer;
1374 private static final Object[] sPbufferLock = new Object[0];
1375
Romain Guy31f2c2e2011-11-21 10:55:41 -08001376 static class Gl20RendererEglContext extends ManagedEGLContext {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001377 final Handler mHandler = new Handler();
1378
Romain Guy31f2c2e2011-11-21 10:55:41 -08001379 public Gl20RendererEglContext(EGLContext context) {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001380 super(context);
1381 }
1382
1383 @Override
1384 public void onTerminate(final EGLContext eglContext) {
1385 // Make sure we do this on the correct thread.
1386 if (mHandler.getLooper() != Looper.myLooper()) {
1387 mHandler.post(new Runnable() {
Romain Guy5d6999e2012-03-22 19:15:04 -07001388 @Override
1389 public void run() {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001390 onTerminate(eglContext);
1391 }
1392 });
1393 return;
1394 }
1395
1396 synchronized (sEglLock) {
1397 if (sEgl == null) return;
1398
1399 if (EGLImpl.getInitCount(sEglDisplay) == 1) {
1400 usePbufferSurface(eglContext);
1401 GLES20Canvas.terminateCaches();
1402
1403 sEgl.eglDestroyContext(sEglDisplay, eglContext);
Romain Guya998dff2012-03-23 18:58:36 -07001404 sEglContextStorage.set(null);
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001405 sEglContextStorage.remove();
1406
1407 sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
Romain Guy31f2c2e2011-11-21 10:55:41 -08001408 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
1409 EGL_NO_SURFACE, EGL_NO_CONTEXT);
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001410
1411 sEgl.eglReleaseThread();
1412 sEgl.eglTerminate(sEglDisplay);
1413
1414 sEgl = null;
1415 sEglDisplay = null;
1416 sEglConfig = null;
1417 sPbuffer = null;
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001418 }
1419 }
1420 }
1421 }
1422
Romain Guye4d01122010-06-16 18:44:05 -07001423 Gl20Renderer(boolean translucent) {
1424 super(2, translucent);
Romain Guye3924992010-06-10 18:51:21 -07001425 }
1426
1427 @Override
Romain Guy5d6999e2012-03-22 19:15:04 -07001428 HardwareCanvas createCanvas() {
Romain Guy6b7bd242010-10-06 19:49:23 -07001429 return mGlCanvas = new GLES20Canvas(mTranslucent);
Romain Guye4d01122010-06-16 18:44:05 -07001430 }
Romain Guye91a9c72011-05-02 14:53:30 -07001431
1432 @Override
Romain Guy5d6999e2012-03-22 19:15:04 -07001433 ManagedEGLContext createManagedContext(EGLContext eglContext) {
1434 return new Gl20Renderer.Gl20RendererEglContext(mEglContext);
1435 }
1436
1437 @Override
Romain Guye91a9c72011-05-02 14:53:30 -07001438 int[] getConfig(boolean dirtyRegions) {
1439 return new int[] {
Romain Guybd431522012-09-26 13:31:25 -07001440 EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
Romain Guy484c7192011-07-25 11:56:33 -07001441 EGL_RED_SIZE, 8,
1442 EGL_GREEN_SIZE, 8,
1443 EGL_BLUE_SIZE, 8,
1444 EGL_ALPHA_SIZE, 8,
1445 EGL_DEPTH_SIZE, 0,
Romain Guy8efca542012-10-15 18:09:49 -07001446 EGL_CONFIG_CAVEAT, EGL_NONE,
Romain Guy7c450aa2012-09-21 19:15:00 -07001447 // TODO: Find a better way to choose the stencil size
1448 EGL_STENCIL_SIZE, mShowOverdraw ? GLES20Canvas.getStencilSize() : 0,
Romain Guy484c7192011-07-25 11:56:33 -07001449 EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
Romain Guybd431522012-09-26 13:31:25 -07001450 (dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
Romain Guy484c7192011-07-25 11:56:33 -07001451 EGL_NONE
Romain Guye91a9c72011-05-02 14:53:30 -07001452 };
1453 }
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001454
1455 @Override
1456 void initCaches() {
1457 GLES20Canvas.initCaches();
1458 }
Romain Guye91a9c72011-05-02 14:53:30 -07001459
Romain Guyb8c0de22010-12-13 14:42:34 -08001460 @Override
1461 boolean canDraw() {
1462 return super.canDraw() && mGlCanvas != null;
1463 }
Romain Guye4d01122010-06-16 18:44:05 -07001464
1465 @Override
Chet Haase44b2fe32012-06-06 19:03:58 -07001466 int onPreDraw(Rect dirty) {
1467 return mGlCanvas.onPreDraw(dirty);
Romain Guye3924992010-06-10 18:51:21 -07001468 }
1469
Romain Guyb025b9c2010-09-16 14:16:48 -07001470 @Override
1471 void onPostDraw() {
1472 mGlCanvas.onPostDraw();
1473 }
1474
Romain Guyb051e892010-09-28 19:09:36 -07001475 @Override
Romain Guy67f27952010-12-07 20:09:23 -08001476 void destroy(boolean full) {
Romain Guyb8c0de22010-12-13 14:42:34 -08001477 try {
1478 super.destroy(full);
1479 } finally {
1480 if (full && mGlCanvas != null) {
1481 mGlCanvas = null;
1482 }
Romain Guy67f27952010-12-07 20:09:23 -08001483 }
1484 }
1485
1486 @Override
Romain Guy9ace8f52011-07-07 20:50:11 -07001487 void setup(int width, int height) {
1488 super.setup(width, height);
1489 if (mVsyncDisabled) {
Romain Guy244ada12012-03-28 16:41:26 -07001490 disableVsync();
Romain Guy9ace8f52011-07-07 20:50:11 -07001491 }
1492 }
1493
1494 @Override
Romain Guy11cb6422012-09-21 00:39:43 -07001495 void pushLayerUpdate(HardwareLayer layer) {
1496 mGlCanvas.pushLayerUpdate(layer);
1497 }
1498
1499 @Override
Romain Guy13631f32012-01-30 17:41:55 -08001500 public DisplayList createDisplayList(String name) {
1501 return new GLES20DisplayList(name);
Romain Guyb051e892010-09-28 19:09:36 -07001502 }
Romain Guyaa6c24c2011-04-28 18:40:04 -07001503
1504 @Override
Romain Guya9489272011-06-22 20:58:11 -07001505 HardwareLayer createHardwareLayer(boolean isOpaque) {
1506 return new GLES20TextureLayer(isOpaque);
Romain Guyaa6c24c2011-04-28 18:40:04 -07001507 }
1508
Romain Guy6c319ca2011-01-11 14:29:25 -08001509 @Override
1510 HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07001511 return new GLES20RenderLayer(width, height, isOpaque);
1512 }
1513
1514 @Override
Romain Guye5e0c502011-06-15 15:18:31 -07001515 SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07001516 return ((GLES20TextureLayer) layer).getSurfaceTexture();
1517 }
1518
Romain Guy6d7475d2011-07-27 16:28:21 -07001519 @Override
Jamie Gennis2af35242012-04-05 11:44:30 -07001520 void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
1521 ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
1522 }
1523
1524 @Override
Romain Guy1ac47652012-04-11 18:15:20 -07001525 boolean safelyRun(Runnable action) {
1526 boolean needsContext = true;
1527 if (isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) needsContext = false;
Romain Guy31f2c2e2011-11-21 10:55:41 -08001528
Romain Guy1ac47652012-04-11 18:15:20 -07001529 if (needsContext) {
1530 Gl20RendererEglContext managedContext =
1531 (Gl20RendererEglContext) sEglContextStorage.get();
1532 if (managedContext == null) return false;
1533 usePbufferSurface(managedContext.getContext());
1534 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08001535
Romain Guy1ac47652012-04-11 18:15:20 -07001536 try {
1537 action.run();
1538 } finally {
Jesse Hall0872b372012-04-02 12:22:51 -07001539 if (needsContext) {
1540 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
1541 EGL_NO_SURFACE, EGL_NO_CONTEXT);
1542 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08001543 }
Romain Guy1ac47652012-04-11 18:15:20 -07001544
1545 return true;
1546 }
1547
1548 @Override
Romain Guybd17bd32012-10-23 19:17:15 -07001549 void destroyLayers(final View view) {
1550 if (view != null) {
1551 safelyRun(new Runnable() {
1552 @Override
1553 public void run() {
1554 if (mCanvas != null) {
1555 mCanvas.clearLayerUpdates();
1556 }
1557 destroyHardwareLayer(view);
1558 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
1559 }
1560 });
1561 }
1562 }
1563
1564 private static void destroyHardwareLayer(View view) {
1565 view.destroyLayer(true);
1566
1567 if (view instanceof ViewGroup) {
1568 ViewGroup group = (ViewGroup) view;
1569
1570 int count = group.getChildCount();
1571 for (int i = 0; i < count; i++) {
1572 destroyHardwareLayer(group.getChildAt(i));
1573 }
1574 }
1575 }
1576
1577 @Override
Romain Guy1ac47652012-04-11 18:15:20 -07001578 void destroyHardwareResources(final View view) {
1579 if (view != null) {
1580 safelyRun(new Runnable() {
1581 @Override
1582 public void run() {
Chet Haase6a2d17f2012-09-30 12:14:13 -07001583 if (mCanvas != null) {
1584 mCanvas.clearLayerUpdates();
1585 }
Romain Guy1ac47652012-04-11 18:15:20 -07001586 destroyResources(view);
1587 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
1588 }
1589 });
1590 }
Romain Guy31f2c2e2011-11-21 10:55:41 -08001591 }
Romain Guy244ada12012-03-28 16:41:26 -07001592
Romain Guy31f2c2e2011-11-21 10:55:41 -08001593 private static void destroyResources(View view) {
1594 view.destroyHardwareResources();
1595
1596 if (view instanceof ViewGroup) {
1597 ViewGroup group = (ViewGroup) view;
1598
1599 int count = group.getChildCount();
1600 for (int i = 0; i < count; i++) {
1601 destroyResources(group.getChildAt(i));
1602 }
1603 }
1604 }
Romain Guy6d7475d2011-07-27 16:28:21 -07001605
1606 static HardwareRenderer create(boolean translucent) {
1607 if (GLES20Canvas.isAvailable()) {
1608 return new Gl20Renderer(translucent);
1609 }
1610 return null;
1611 }
1612
Romain Guy19f86e82012-04-23 15:19:07 -07001613 static void startTrimMemory(int level) {
Romain Guy912a7b32011-07-26 18:57:28 -07001614 if (sEgl == null || sEglConfig == null) return;
1615
Romain Guy5d6999e2012-03-22 19:15:04 -07001616 Gl20RendererEglContext managedContext =
1617 (Gl20RendererEglContext) sEglContextStorage.get();
Romain Guy912a7b32011-07-26 18:57:28 -07001618 // We do not have OpenGL objects
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001619 if (managedContext == null) {
Romain Guy912a7b32011-07-26 18:57:28 -07001620 return;
1621 } else {
Dianne Hackborn717a25d2011-11-15 18:59:59 -08001622 usePbufferSurface(managedContext.getContext());
Romain Guye3924992010-06-10 18:51:21 -07001623 }
Romain Guy912a7b32011-07-26 18:57:28 -07001624
Dianne Hackborn27ff9132012-03-06 14:57:58 -08001625 if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
1626 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
1627 } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
1628 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
Romain Guybdf76092011-07-18 15:00:43 -07001629 }
Romain Guy19f86e82012-04-23 15:19:07 -07001630 }
Jesse Hall0872b372012-04-02 12:22:51 -07001631
Romain Guy19f86e82012-04-23 15:19:07 -07001632 static void endTrimMemory() {
1633 if (sEgl != null && sEglDisplay != null) {
1634 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1635 }
Romain Guybdf76092011-07-18 15:00:43 -07001636 }
Romain Guy8ff6b9e2011-11-09 20:10:18 -08001637
1638 private static void usePbufferSurface(EGLContext eglContext) {
1639 synchronized (sPbufferLock) {
1640 // Create a temporary 1x1 pbuffer so we have a context
1641 // to clear our OpenGL objects
1642 if (sPbuffer == null) {
1643 sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
1644 EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
1645 });
1646 }
1647 }
1648 sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
1649 }
Romain Guye3924992010-06-10 18:51:21 -07001650 }
Romain Guy2d614592010-06-09 18:21:37 -07001651}