blob: 3f5f6c42cf6839acdb5c398449b72edbf337b936 [file] [log] [blame]
John Reckcec24ae2013-11-05 13:27:50 -08001/*
2 * Copyright (C) 2013 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
17package android.view;
18
John Reckb8802b12014-06-16 15:28:50 -070019import android.content.Context;
20import android.content.res.Resources;
John Reck04fc5832014-02-05 16:38:25 -080021import android.graphics.Bitmap;
John Reckcec24ae2013-11-05 13:27:50 -080022import android.graphics.Rect;
23import android.graphics.SurfaceTexture;
John Reckb8802b12014-06-16 15:28:50 -070024import android.graphics.drawable.Drawable;
John Reck66f0be62014-05-13 13:39:31 -070025import android.os.IBinder;
26import android.os.RemoteException;
27import android.os.ServiceManager;
John Reckfe5e7b72014-05-23 17:42:28 -070028import android.os.SystemProperties;
John Reckcec24ae2013-11-05 13:27:50 -080029import android.os.Trace;
John Reck66f0be62014-05-13 13:39:31 -070030import android.util.Log;
John Reckb8802b12014-06-16 15:28:50 -070031import android.util.LongSparseArray;
John Reck315c3292014-05-09 19:21:04 -070032import android.util.TimeUtils;
John Reckcec24ae2013-11-05 13:27:50 -080033import android.view.Surface.OutOfResourcesException;
34import android.view.View.AttachInfo;
35
John Reckfe5e7b72014-05-23 17:42:28 -070036import java.io.FileDescriptor;
John Reckcec24ae2013-11-05 13:27:50 -080037import java.io.PrintWriter;
John Reckb8802b12014-06-16 15:28:50 -070038import java.util.ArrayList;
39import java.util.Collections;
40import java.util.Comparator;
41import java.util.HashSet;
John Reckcec24ae2013-11-05 13:27:50 -080042
43/**
44 * Hardware renderer that proxies the rendering to a render thread. Most calls
John Reck4f02bf42014-01-03 18:09:17 -080045 * are currently synchronous.
John Reckcec24ae2013-11-05 13:27:50 -080046 *
47 * The UI thread can block on the RenderThread, but RenderThread must never
48 * block on the UI thread.
49 *
John Reck4f02bf42014-01-03 18:09:17 -080050 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates
51 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed
52 * by the lifecycle of the RenderProxy.
53 *
John Reckcec24ae2013-11-05 13:27:50 -080054 * Note that although currently the EGL context & surfaces are created & managed
55 * by the render thread, the goal is to move that into a shared structure that can
56 * be managed by both threads. EGLSurface creation & deletion should ideally be
57 * done on the UI thread and not the RenderThread to avoid stalling the
58 * RenderThread with surface buffer allocation.
59 *
60 * @hide
61 */
62public class ThreadedRenderer extends HardwareRenderer {
63 private static final String LOGTAG = "ThreadedRenderer";
64
John Reckf9be7792014-05-02 18:21:16 -070065 // Keep in sync with DrawFrameTask.h SYNC_* flags
66 // Nothing interesting to report
67 private static final int SYNC_OK = 0x0;
68 // Needs a ViewRoot invalidate
69 private static final int SYNC_INVALIDATE_REQUIRED = 0x1;
70
John Reckfe5e7b72014-05-23 17:42:28 -070071 private static final String[] VISUALIZERS = {
72 PROFILE_PROPERTY_VISUALIZE_BARS,
73 };
74
John Reckcec24ae2013-11-05 13:27:50 -080075 private int mWidth, mHeight;
John Reck4f02bf42014-01-03 18:09:17 -080076 private long mNativeProxy;
John Reckf7d9c1d2014-04-09 10:01:03 -070077 private boolean mInitialized = false;
John Reckbc0cc022014-04-11 16:08:14 -070078 private RenderNode mRootNode;
John Reck18f16e62014-05-02 16:46:41 -070079 private Choreographer mChoreographer;
John Reckfe5e7b72014-05-23 17:42:28 -070080 private boolean mProfilingEnabled;
John Reckcec24ae2013-11-05 13:27:50 -080081
John Reckb8802b12014-06-16 15:28:50 -070082 ThreadedRenderer(Context context, boolean translucent) {
83 AtlasInitializer.sInstance.init(context);
John Reck66f0be62014-05-13 13:39:31 -070084
John Recke45b1fd2014-04-15 09:50:16 -070085 long rootNodePtr = nCreateRootRenderNode();
86 mRootNode = RenderNode.adopt(rootNodePtr);
John Reckbc0cc022014-04-11 16:08:14 -070087 mRootNode.setClipToBounds(false);
John Recke45b1fd2014-04-15 09:50:16 -070088 mNativeProxy = nCreateProxy(translucent, rootNodePtr);
John Reck18f16e62014-05-02 16:46:41 -070089
90 // Setup timing
91 mChoreographer = Choreographer.getInstance();
92 nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
John Reckfe5e7b72014-05-23 17:42:28 -070093
94 loadSystemProperties();
John Reckcec24ae2013-11-05 13:27:50 -080095 }
96
97 @Override
98 void destroy(boolean full) {
John Reckf7d9c1d2014-04-09 10:01:03 -070099 mInitialized = false;
100 updateEnabledState(null);
John Reckfae904d2014-04-14 11:01:57 -0700101 nDestroyCanvasAndSurface(mNativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -0800102 }
103
John Reckf7d9c1d2014-04-09 10:01:03 -0700104 private void updateEnabledState(Surface surface) {
105 if (surface == null || !surface.isValid()) {
106 setEnabled(false);
107 } else {
108 setEnabled(mInitialized);
109 }
110 }
111
John Reckcec24ae2013-11-05 13:27:50 -0800112 @Override
113 boolean initialize(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700114 mInitialized = true;
115 updateEnabledState(surface);
Dan Stoza5795d642014-06-20 13:01:36 -0700116 boolean status = nInitialize(mNativeProxy, surface);
117 surface.allocateBuffers();
118 return status;
John Reckcec24ae2013-11-05 13:27:50 -0800119 }
120
121 @Override
122 void updateSurface(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700123 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -0800124 nUpdateSurface(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800125 }
126
127 @Override
John Reckf7d9c1d2014-04-09 10:01:03 -0700128 void pauseSurface(Surface surface) {
129 nPauseSurface(mNativeProxy, surface);
130 }
131
132 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800133 void destroyHardwareResources(View view) {
John Reck4f02bf42014-01-03 18:09:17 -0800134 destroyResources(view);
John Recke1628b72014-05-23 15:11:19 -0700135 nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS);
John Reck4f02bf42014-01-03 18:09:17 -0800136 }
137
138 private static void destroyResources(View view) {
139 view.destroyHardwareResources();
140
141 if (view instanceof ViewGroup) {
142 ViewGroup group = (ViewGroup) view;
143
144 int count = group.getChildCount();
145 for (int i = 0; i < count; i++) {
146 destroyResources(group.getChildAt(i));
147 }
148 }
John Reckcec24ae2013-11-05 13:27:50 -0800149 }
150
151 @Override
152 void invalidate(Surface surface) {
John Reck4f02bf42014-01-03 18:09:17 -0800153 updateSurface(surface);
John Reckcec24ae2013-11-05 13:27:50 -0800154 }
155
156 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800157 boolean safelyRun(Runnable action) {
John Reckfc53ef272014-02-11 10:40:25 -0800158 nRunWithGlContext(mNativeProxy, action);
159 return true;
John Reckcec24ae2013-11-05 13:27:50 -0800160 }
161
162 @Override
Chris Craik797b95b2014-05-20 18:10:25 -0700163 void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) {
John Reckcec24ae2013-11-05 13:27:50 -0800164 mWidth = width;
165 mHeight = height;
John Reckbc0cc022014-04-11 16:08:14 -0700166 mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
Chris Craik797b95b2014-05-20 18:10:25 -0700167 nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius);
John Reckcec24ae2013-11-05 13:27:50 -0800168 }
169
170 @Override
John Reck63a06672014-05-07 13:45:54 -0700171 void setOpaque(boolean opaque) {
172 nSetOpaque(mNativeProxy, opaque);
173 }
174
175 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800176 int getWidth() {
177 return mWidth;
178 }
179
180 @Override
181 int getHeight() {
182 return mHeight;
183 }
184
185 @Override
John Reckfe5e7b72014-05-23 17:42:28 -0700186 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
187 pw.flush();
188 nDumpProfileInfo(mNativeProxy, fd);
John Reckcec24ae2013-11-05 13:27:50 -0800189 }
190
John Reckfe5e7b72014-05-23 17:42:28 -0700191 private static int search(String[] values, String value) {
192 for (int i = 0; i < values.length; i++) {
193 if (values[i].equals(value)) return i;
194 }
195 return -1;
196 }
197
198 private static boolean checkIfProfilingRequested() {
199 String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY);
200 int graphType = search(VISUALIZERS, profiling);
201 return (graphType >= 0) || Boolean.parseBoolean(profiling);
John Reckcec24ae2013-11-05 13:27:50 -0800202 }
203
204 @Override
205 boolean loadSystemProperties() {
John Reckfe5e7b72014-05-23 17:42:28 -0700206 boolean changed = nLoadSystemProperties(mNativeProxy);
207 boolean wantProfiling = checkIfProfilingRequested();
208 if (wantProfiling != mProfilingEnabled) {
209 mProfilingEnabled = wantProfiling;
210 changed = true;
211 }
212 return changed;
John Reckcec24ae2013-11-05 13:27:50 -0800213 }
214
John Reckbc0cc022014-04-11 16:08:14 -0700215 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
John Reckcec24ae2013-11-05 13:27:50 -0800216 view.mPrivateFlags |= View.PFLAG_DRAWN;
217
218 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
219 == View.PFLAG_INVALIDATED;
220 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
221
222 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
John Reckbc0cc022014-04-11 16:08:14 -0700223 HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
John Reck05e85842014-04-23 14:48:28 -0700224 try {
John Reck86faf9e2014-05-19 13:19:07 -0700225 canvas.save();
Alan Viveretted5b2ec42014-05-17 16:34:09 -0700226 callbacks.onHardwarePreDraw(canvas);
John Reck05e85842014-04-23 14:48:28 -0700227 canvas.drawDisplayList(view.getDisplayList());
228 callbacks.onHardwarePostDraw(canvas);
John Reck86faf9e2014-05-19 13:19:07 -0700229 canvas.restore();
John Reck05e85842014-04-23 14:48:28 -0700230 } finally {
231 mRootNode.end(canvas);
232 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
233 }
John Reckcec24ae2013-11-05 13:27:50 -0800234
235 view.mRecreateDisplayList = false;
John Reckbc0cc022014-04-11 16:08:14 -0700236 }
237
238 @Override
John Recke4267ea2014-06-03 15:53:15 -0700239 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
John Reckbc0cc022014-04-11 16:08:14 -0700240 attachInfo.mIgnoreDirtyState = true;
John Reck18f16e62014-05-02 16:46:41 -0700241 long frameTimeNanos = mChoreographer.getFrameTimeNanos();
John Reck315c3292014-05-09 19:21:04 -0700242 attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
John Reckbc0cc022014-04-11 16:08:14 -0700243
John Reckfe5e7b72014-05-23 17:42:28 -0700244 long recordDuration = 0;
245 if (mProfilingEnabled) {
246 recordDuration = System.nanoTime();
247 }
248
John Reckbc0cc022014-04-11 16:08:14 -0700249 updateRootDisplayList(view, callbacks);
John Reckcec24ae2013-11-05 13:27:50 -0800250
John Reckfe5e7b72014-05-23 17:42:28 -0700251 if (mProfilingEnabled) {
252 recordDuration = System.nanoTime() - recordDuration;
253 }
254
John Reck6313b922014-04-16 18:59:21 -0700255 attachInfo.mIgnoreDirtyState = false;
256
John Reckf9be7792014-05-02 18:21:16 -0700257 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
John Recke4267ea2014-06-03 15:53:15 -0700258 recordDuration, view.getResources().getDisplayMetrics().density);
John Reckf9be7792014-05-02 18:21:16 -0700259 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
260 attachInfo.mViewRootImpl.invalidate();
261 }
John Reckcec24ae2013-11-05 13:27:50 -0800262 }
263
264 @Override
Bo Liuae738a72014-04-27 16:22:04 -0700265 void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck0d1f6342014-03-28 20:30:27 -0700266 nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
267 }
268
269 @Override
John Reck19b6bcf2014-02-14 20:03:38 -0800270 HardwareLayer createTextureLayer() {
271 long layer = nCreateTextureLayer(mNativeProxy);
272 return HardwareLayer.adoptTextureLayer(this, layer);
273 }
274
275 @Override
276 SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
277 final SurfaceTexture[] ret = new SurfaceTexture[1];
278 nRunWithGlContext(mNativeProxy, new Runnable() {
279 @Override
280 public void run() {
281 ret[0] = layer.createSurfaceTexture();
282 }
283 });
284 return ret[0];
285 }
286
287 @Override
288 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
289 return nCopyLayerInto(mNativeProxy,
290 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
291 }
292
293 @Override
294 void pushLayerUpdate(HardwareLayer layer) {
John Reckd72e0a32014-05-29 18:56:11 -0700295 nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
John Reck19b6bcf2014-02-14 20:03:38 -0800296 }
297
298 @Override
299 void flushLayerUpdates() {
300 // TODO: Figure out what this should do or remove it
301 }
302
303 @Override
304 void onLayerDestroyed(HardwareLayer layer) {
John Reckd72e0a32014-05-29 18:56:11 -0700305 nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
John Reck19b6bcf2014-02-14 20:03:38 -0800306 }
307
308 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800309 void setName(String name) {
John Reckcec24ae2013-11-05 13:27:50 -0800310 }
311
John Reck4f02bf42014-01-03 18:09:17 -0800312 @Override
John Reck28ad7b52014-04-07 16:59:25 -0700313 void fence() {
314 nFence(mNativeProxy);
315 }
316
317 @Override
John Recka5dda642014-05-22 15:43:54 -0700318 public void notifyFramePending() {
319 nNotifyFramePending(mNativeProxy);
320 }
321
322 @Override
John Reck4f02bf42014-01-03 18:09:17 -0800323 protected void finalize() throws Throwable {
324 try {
325 nDeleteProxy(mNativeProxy);
John Reck0ed751d2014-04-08 14:10:17 -0700326 mNativeProxy = 0;
John Reck4f02bf42014-01-03 18:09:17 -0800327 } finally {
328 super.finalize();
John Reckcec24ae2013-11-05 13:27:50 -0800329 }
330 }
331
John Reck84a4c882014-05-30 14:34:03 -0700332 static void startTrimMemory(int level) {
333 // TODO
334 }
335
336 static void endTrimMemory() {
337 // TODO
338 }
339
John Reck66f0be62014-05-13 13:39:31 -0700340 private static class AtlasInitializer {
341 static AtlasInitializer sInstance = new AtlasInitializer();
342
343 private boolean mInitialized = false;
344
345 private AtlasInitializer() {}
346
John Reckb8802b12014-06-16 15:28:50 -0700347 synchronized void init(Context context) {
John Reck66f0be62014-05-13 13:39:31 -0700348 if (mInitialized) return;
349 IBinder binder = ServiceManager.getService("assetatlas");
350 if (binder == null) return;
351
352 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
353 try {
354 if (atlas.isCompatible(android.os.Process.myPpid())) {
355 GraphicBuffer buffer = atlas.getBuffer();
356 if (buffer != null) {
357 long[] map = atlas.getMap();
358 if (map != null) {
John Reckb8802b12014-06-16 15:28:50 -0700359 // TODO Remove after fixing b/15425820
360 validateMap(context, map);
John Reck66f0be62014-05-13 13:39:31 -0700361 nSetAtlas(buffer, map);
362 mInitialized = true;
363 }
364 // If IAssetAtlas is not the same class as the IBinder
365 // we are using a remote service and we can safely
366 // destroy the graphic buffer
367 if (atlas.getClass() != binder.getClass()) {
368 buffer.destroy();
369 }
370 }
371 }
372 } catch (RemoteException e) {
373 Log.w(LOG_TAG, "Could not acquire atlas", e);
374 }
375 }
John Reckb8802b12014-06-16 15:28:50 -0700376
377 private static void validateMap(Context context, long[] map) {
378 Log.d("Atlas", "Validating map...");
379 HashSet<Long> preloadedPointers = new HashSet<Long>();
380
381 // We only care about drawables that hold bitmaps
382 final Resources resources = context.getResources();
383 final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
384
385 final int count = drawables.size();
386 for (int i = 0; i < count; i++) {
387 final Bitmap bitmap = drawables.valueAt(i).getBitmap();
388 if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
389 preloadedPointers.add(bitmap.mNativeBitmap);
390 }
391 }
392
393 for (int i = 0; i < map.length; i += 4) {
394 if (!preloadedPointers.contains(map[i])) {
395 Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i]));
396 map[i] = 0;
397 }
398 }
399 }
John Reck66f0be62014-05-13 13:39:31 -0700400 }
401
John Reck84a4c882014-05-30 14:34:03 -0700402 static native void setupShadersDiskCache(String cacheFile);
403
John Reck66f0be62014-05-13 13:39:31 -0700404 private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
John Reck4f02bf42014-01-03 18:09:17 -0800405
John Recke45b1fd2014-04-15 09:50:16 -0700406 private static native long nCreateRootRenderNode();
407 private static native long nCreateProxy(boolean translucent, long rootRenderNode);
John Reck4f02bf42014-01-03 18:09:17 -0800408 private static native void nDeleteProxy(long nativeProxy);
409
John Reck18f16e62014-05-02 16:46:41 -0700410 private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
John Recke4280ba2014-05-05 16:39:37 -0700411 private static native boolean nLoadSystemProperties(long nativeProxy);
John Reck18f16e62014-05-02 16:46:41 -0700412
John Reck4f02bf42014-01-03 18:09:17 -0800413 private static native boolean nInitialize(long nativeProxy, Surface window);
414 private static native void nUpdateSurface(long nativeProxy, Surface window);
John Reckf7d9c1d2014-04-09 10:01:03 -0700415 private static native void nPauseSurface(long nativeProxy, Surface window);
Chris Craik797b95b2014-05-20 18:10:25 -0700416 private static native void nSetup(long nativeProxy, int width, int height,
417 float lightX, float lightY, float lightZ, float lightRadius);
John Reck63a06672014-05-07 13:45:54 -0700418 private static native void nSetOpaque(long nativeProxy, boolean opaque);
John Reckfe5e7b72014-05-23 17:42:28 -0700419 private static native int nSyncAndDrawFrame(long nativeProxy,
John Recke4267ea2014-06-03 15:53:15 -0700420 long frameTimeNanos, long recordDuration, float density);
John Reckfc53ef272014-02-11 10:40:25 -0800421 private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
John Reckfae904d2014-04-14 11:01:57 -0700422 private static native void nDestroyCanvasAndSurface(long nativeProxy);
John Reck4f02bf42014-01-03 18:09:17 -0800423
John Reck0d1f6342014-03-28 20:30:27 -0700424 private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
John Reck19b6bcf2014-02-14 20:03:38 -0800425
426 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
427 private static native long nCreateTextureLayer(long nativeProxy);
428 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
John Reckd72e0a32014-05-29 18:56:11 -0700429 private static native void nPushLayerUpdate(long nativeProxy, long layer);
430 private static native void nCancelLayerUpdate(long nativeProxy, long layer);
John Reck28ad7b52014-04-07 16:59:25 -0700431
John Recke1628b72014-05-23 15:11:19 -0700432 private static native void nFlushCaches(long nativeProxy, int flushMode);
433
John Reck28ad7b52014-04-07 16:59:25 -0700434 private static native void nFence(long nativeProxy);
John Recka5dda642014-05-22 15:43:54 -0700435 private static native void nNotifyFramePending(long nativeProxy);
John Reckfe5e7b72014-05-23 17:42:28 -0700436
437 private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
John Reckcec24ae2013-11-05 13:27:50 -0800438}