blob: 166edc247176dfd65183eb1120a71ed8ddf39b55 [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);
John Reck4f02bf42014-01-03 18:09:17 -0800116 return nInitialize(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800117 }
118
119 @Override
120 void updateSurface(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700121 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -0800122 nUpdateSurface(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800123 }
124
125 @Override
John Reckf7d9c1d2014-04-09 10:01:03 -0700126 void pauseSurface(Surface surface) {
127 nPauseSurface(mNativeProxy, surface);
128 }
129
130 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800131 void destroyHardwareResources(View view) {
John Reck4f02bf42014-01-03 18:09:17 -0800132 destroyResources(view);
John Recke1628b72014-05-23 15:11:19 -0700133 nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS);
John Reck4f02bf42014-01-03 18:09:17 -0800134 }
135
136 private static void destroyResources(View view) {
137 view.destroyHardwareResources();
138
139 if (view instanceof ViewGroup) {
140 ViewGroup group = (ViewGroup) view;
141
142 int count = group.getChildCount();
143 for (int i = 0; i < count; i++) {
144 destroyResources(group.getChildAt(i));
145 }
146 }
John Reckcec24ae2013-11-05 13:27:50 -0800147 }
148
149 @Override
150 void invalidate(Surface surface) {
John Reck4f02bf42014-01-03 18:09:17 -0800151 updateSurface(surface);
John Reckcec24ae2013-11-05 13:27:50 -0800152 }
153
154 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800155 boolean safelyRun(Runnable action) {
John Reckfc53ef272014-02-11 10:40:25 -0800156 nRunWithGlContext(mNativeProxy, action);
157 return true;
John Reckcec24ae2013-11-05 13:27:50 -0800158 }
159
160 @Override
Chris Craik797b95b2014-05-20 18:10:25 -0700161 void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) {
John Reckcec24ae2013-11-05 13:27:50 -0800162 mWidth = width;
163 mHeight = height;
John Reckbc0cc022014-04-11 16:08:14 -0700164 mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
Chris Craik797b95b2014-05-20 18:10:25 -0700165 nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius);
John Reckcec24ae2013-11-05 13:27:50 -0800166 }
167
168 @Override
John Reck63a06672014-05-07 13:45:54 -0700169 void setOpaque(boolean opaque) {
170 nSetOpaque(mNativeProxy, opaque);
171 }
172
173 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800174 int getWidth() {
175 return mWidth;
176 }
177
178 @Override
179 int getHeight() {
180 return mHeight;
181 }
182
183 @Override
John Reckfe5e7b72014-05-23 17:42:28 -0700184 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
185 pw.flush();
186 nDumpProfileInfo(mNativeProxy, fd);
John Reckcec24ae2013-11-05 13:27:50 -0800187 }
188
John Reckfe5e7b72014-05-23 17:42:28 -0700189 private static int search(String[] values, String value) {
190 for (int i = 0; i < values.length; i++) {
191 if (values[i].equals(value)) return i;
192 }
193 return -1;
194 }
195
196 private static boolean checkIfProfilingRequested() {
197 String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY);
198 int graphType = search(VISUALIZERS, profiling);
199 return (graphType >= 0) || Boolean.parseBoolean(profiling);
John Reckcec24ae2013-11-05 13:27:50 -0800200 }
201
202 @Override
203 boolean loadSystemProperties() {
John Reckfe5e7b72014-05-23 17:42:28 -0700204 boolean changed = nLoadSystemProperties(mNativeProxy);
205 boolean wantProfiling = checkIfProfilingRequested();
206 if (wantProfiling != mProfilingEnabled) {
207 mProfilingEnabled = wantProfiling;
208 changed = true;
209 }
210 return changed;
John Reckcec24ae2013-11-05 13:27:50 -0800211 }
212
John Reckbc0cc022014-04-11 16:08:14 -0700213 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
John Reckcec24ae2013-11-05 13:27:50 -0800214 view.mPrivateFlags |= View.PFLAG_DRAWN;
215
216 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
217 == View.PFLAG_INVALIDATED;
218 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
219
220 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
John Reckbc0cc022014-04-11 16:08:14 -0700221 HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
John Reck05e85842014-04-23 14:48:28 -0700222 try {
John Reck86faf9e2014-05-19 13:19:07 -0700223 canvas.save();
Alan Viveretted5b2ec42014-05-17 16:34:09 -0700224 callbacks.onHardwarePreDraw(canvas);
John Reck05e85842014-04-23 14:48:28 -0700225 canvas.drawDisplayList(view.getDisplayList());
226 callbacks.onHardwarePostDraw(canvas);
John Reck86faf9e2014-05-19 13:19:07 -0700227 canvas.restore();
John Reck05e85842014-04-23 14:48:28 -0700228 } finally {
229 mRootNode.end(canvas);
230 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
231 }
John Reckcec24ae2013-11-05 13:27:50 -0800232
233 view.mRecreateDisplayList = false;
John Reckbc0cc022014-04-11 16:08:14 -0700234 }
235
236 @Override
John Recke4267ea2014-06-03 15:53:15 -0700237 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
John Reckbc0cc022014-04-11 16:08:14 -0700238 attachInfo.mIgnoreDirtyState = true;
John Reck18f16e62014-05-02 16:46:41 -0700239 long frameTimeNanos = mChoreographer.getFrameTimeNanos();
John Reck315c3292014-05-09 19:21:04 -0700240 attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
John Reckbc0cc022014-04-11 16:08:14 -0700241
John Reckfe5e7b72014-05-23 17:42:28 -0700242 long recordDuration = 0;
243 if (mProfilingEnabled) {
244 recordDuration = System.nanoTime();
245 }
246
John Reckbc0cc022014-04-11 16:08:14 -0700247 updateRootDisplayList(view, callbacks);
John Reckcec24ae2013-11-05 13:27:50 -0800248
John Reckfe5e7b72014-05-23 17:42:28 -0700249 if (mProfilingEnabled) {
250 recordDuration = System.nanoTime() - recordDuration;
251 }
252
John Reck6313b922014-04-16 18:59:21 -0700253 attachInfo.mIgnoreDirtyState = false;
254
John Reckf9be7792014-05-02 18:21:16 -0700255 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
John Recke4267ea2014-06-03 15:53:15 -0700256 recordDuration, view.getResources().getDisplayMetrics().density);
John Reckf9be7792014-05-02 18:21:16 -0700257 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
258 attachInfo.mViewRootImpl.invalidate();
259 }
John Reckcec24ae2013-11-05 13:27:50 -0800260 }
261
262 @Override
Bo Liuae738a72014-04-27 16:22:04 -0700263 void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck0d1f6342014-03-28 20:30:27 -0700264 nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
265 }
266
267 @Override
John Reck19b6bcf2014-02-14 20:03:38 -0800268 HardwareLayer createTextureLayer() {
269 long layer = nCreateTextureLayer(mNativeProxy);
270 return HardwareLayer.adoptTextureLayer(this, layer);
271 }
272
273 @Override
274 SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
275 final SurfaceTexture[] ret = new SurfaceTexture[1];
276 nRunWithGlContext(mNativeProxy, new Runnable() {
277 @Override
278 public void run() {
279 ret[0] = layer.createSurfaceTexture();
280 }
281 });
282 return ret[0];
283 }
284
285 @Override
286 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
287 return nCopyLayerInto(mNativeProxy,
288 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
289 }
290
291 @Override
292 void pushLayerUpdate(HardwareLayer layer) {
John Reckd72e0a32014-05-29 18:56:11 -0700293 nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
John Reck19b6bcf2014-02-14 20:03:38 -0800294 }
295
296 @Override
297 void flushLayerUpdates() {
298 // TODO: Figure out what this should do or remove it
299 }
300
301 @Override
302 void onLayerDestroyed(HardwareLayer layer) {
John Reckd72e0a32014-05-29 18:56:11 -0700303 nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
John Reck19b6bcf2014-02-14 20:03:38 -0800304 }
305
306 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800307 void setName(String name) {
John Reckcec24ae2013-11-05 13:27:50 -0800308 }
309
John Reck4f02bf42014-01-03 18:09:17 -0800310 @Override
John Reck28ad7b52014-04-07 16:59:25 -0700311 void fence() {
312 nFence(mNativeProxy);
313 }
314
315 @Override
John Recka5dda642014-05-22 15:43:54 -0700316 public void notifyFramePending() {
317 nNotifyFramePending(mNativeProxy);
318 }
319
320 @Override
John Reck4f02bf42014-01-03 18:09:17 -0800321 protected void finalize() throws Throwable {
322 try {
323 nDeleteProxy(mNativeProxy);
John Reck0ed751d2014-04-08 14:10:17 -0700324 mNativeProxy = 0;
John Reck4f02bf42014-01-03 18:09:17 -0800325 } finally {
326 super.finalize();
John Reckcec24ae2013-11-05 13:27:50 -0800327 }
328 }
329
John Reck84a4c882014-05-30 14:34:03 -0700330 static void startTrimMemory(int level) {
331 // TODO
332 }
333
334 static void endTrimMemory() {
335 // TODO
336 }
337
John Reck66f0be62014-05-13 13:39:31 -0700338 private static class AtlasInitializer {
339 static AtlasInitializer sInstance = new AtlasInitializer();
340
341 private boolean mInitialized = false;
342
343 private AtlasInitializer() {}
344
John Reckb8802b12014-06-16 15:28:50 -0700345 synchronized void init(Context context) {
John Reck66f0be62014-05-13 13:39:31 -0700346 if (mInitialized) return;
347 IBinder binder = ServiceManager.getService("assetatlas");
348 if (binder == null) return;
349
350 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
351 try {
352 if (atlas.isCompatible(android.os.Process.myPpid())) {
353 GraphicBuffer buffer = atlas.getBuffer();
354 if (buffer != null) {
355 long[] map = atlas.getMap();
356 if (map != null) {
John Reckb8802b12014-06-16 15:28:50 -0700357 // TODO Remove after fixing b/15425820
358 validateMap(context, map);
John Reck66f0be62014-05-13 13:39:31 -0700359 nSetAtlas(buffer, map);
360 mInitialized = true;
361 }
362 // If IAssetAtlas is not the same class as the IBinder
363 // we are using a remote service and we can safely
364 // destroy the graphic buffer
365 if (atlas.getClass() != binder.getClass()) {
366 buffer.destroy();
367 }
368 }
369 }
370 } catch (RemoteException e) {
371 Log.w(LOG_TAG, "Could not acquire atlas", e);
372 }
373 }
John Reckb8802b12014-06-16 15:28:50 -0700374
375 private static void validateMap(Context context, long[] map) {
376 Log.d("Atlas", "Validating map...");
377 HashSet<Long> preloadedPointers = new HashSet<Long>();
378
379 // We only care about drawables that hold bitmaps
380 final Resources resources = context.getResources();
381 final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
382
383 final int count = drawables.size();
384 for (int i = 0; i < count; i++) {
385 final Bitmap bitmap = drawables.valueAt(i).getBitmap();
386 if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
387 preloadedPointers.add(bitmap.mNativeBitmap);
388 }
389 }
390
391 for (int i = 0; i < map.length; i += 4) {
392 if (!preloadedPointers.contains(map[i])) {
393 Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i]));
394 map[i] = 0;
395 }
396 }
397 }
John Reck66f0be62014-05-13 13:39:31 -0700398 }
399
John Reck84a4c882014-05-30 14:34:03 -0700400 static native void setupShadersDiskCache(String cacheFile);
401
John Reck66f0be62014-05-13 13:39:31 -0700402 private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
John Reck4f02bf42014-01-03 18:09:17 -0800403
John Recke45b1fd2014-04-15 09:50:16 -0700404 private static native long nCreateRootRenderNode();
405 private static native long nCreateProxy(boolean translucent, long rootRenderNode);
John Reck4f02bf42014-01-03 18:09:17 -0800406 private static native void nDeleteProxy(long nativeProxy);
407
John Reck18f16e62014-05-02 16:46:41 -0700408 private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
John Recke4280ba2014-05-05 16:39:37 -0700409 private static native boolean nLoadSystemProperties(long nativeProxy);
John Reck18f16e62014-05-02 16:46:41 -0700410
John Reck4f02bf42014-01-03 18:09:17 -0800411 private static native boolean nInitialize(long nativeProxy, Surface window);
412 private static native void nUpdateSurface(long nativeProxy, Surface window);
John Reckf7d9c1d2014-04-09 10:01:03 -0700413 private static native void nPauseSurface(long nativeProxy, Surface window);
Chris Craik797b95b2014-05-20 18:10:25 -0700414 private static native void nSetup(long nativeProxy, int width, int height,
415 float lightX, float lightY, float lightZ, float lightRadius);
John Reck63a06672014-05-07 13:45:54 -0700416 private static native void nSetOpaque(long nativeProxy, boolean opaque);
John Reckfe5e7b72014-05-23 17:42:28 -0700417 private static native int nSyncAndDrawFrame(long nativeProxy,
John Recke4267ea2014-06-03 15:53:15 -0700418 long frameTimeNanos, long recordDuration, float density);
John Reckfc53ef272014-02-11 10:40:25 -0800419 private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
John Reckfae904d2014-04-14 11:01:57 -0700420 private static native void nDestroyCanvasAndSurface(long nativeProxy);
John Reck4f02bf42014-01-03 18:09:17 -0800421
John Reck0d1f6342014-03-28 20:30:27 -0700422 private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
John Reck19b6bcf2014-02-14 20:03:38 -0800423
424 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
425 private static native long nCreateTextureLayer(long nativeProxy);
426 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
John Reckd72e0a32014-05-29 18:56:11 -0700427 private static native void nPushLayerUpdate(long nativeProxy, long layer);
428 private static native void nCancelLayerUpdate(long nativeProxy, long layer);
John Reck28ad7b52014-04-07 16:59:25 -0700429
John Recke1628b72014-05-23 15:11:19 -0700430 private static native void nFlushCaches(long nativeProxy, int flushMode);
431
John Reck28ad7b52014-04-07 16:59:25 -0700432 private static native void nFence(long nativeProxy);
John Recka5dda642014-05-22 15:43:54 -0700433 private static native void nNotifyFramePending(long nativeProxy);
John Reckfe5e7b72014-05-23 17:42:28 -0700434
435 private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
John Reckcec24ae2013-11-05 13:27:50 -0800436}