blob: 45714ff872c8f777b3c753879ca483bd0911e8bb [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 Reckb8802b12014-06-16 15:28:50 -070022import android.graphics.drawable.Drawable;
John Reck66f0be62014-05-13 13:39:31 -070023import android.os.IBinder;
24import android.os.RemoteException;
25import android.os.ServiceManager;
John Reckfe5e7b72014-05-23 17:42:28 -070026import android.os.SystemProperties;
John Reckcec24ae2013-11-05 13:27:50 -080027import android.os.Trace;
John Reck66f0be62014-05-13 13:39:31 -070028import android.util.Log;
John Reckb8802b12014-06-16 15:28:50 -070029import android.util.LongSparseArray;
John Reck315c3292014-05-09 19:21:04 -070030import android.util.TimeUtils;
John Reckcec24ae2013-11-05 13:27:50 -080031import android.view.Surface.OutOfResourcesException;
32import android.view.View.AttachInfo;
33
John Reckfe5e7b72014-05-23 17:42:28 -070034import java.io.FileDescriptor;
John Reckcec24ae2013-11-05 13:27:50 -080035import java.io.PrintWriter;
John Reckb8802b12014-06-16 15:28:50 -070036import java.util.HashSet;
John Reckcec24ae2013-11-05 13:27:50 -080037
38/**
39 * Hardware renderer that proxies the rendering to a render thread. Most calls
John Reck4f02bf42014-01-03 18:09:17 -080040 * are currently synchronous.
John Reckcec24ae2013-11-05 13:27:50 -080041 *
42 * The UI thread can block on the RenderThread, but RenderThread must never
43 * block on the UI thread.
44 *
John Reck4f02bf42014-01-03 18:09:17 -080045 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates
46 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed
47 * by the lifecycle of the RenderProxy.
48 *
John Reckcec24ae2013-11-05 13:27:50 -080049 * Note that although currently the EGL context & surfaces are created & managed
50 * by the render thread, the goal is to move that into a shared structure that can
51 * be managed by both threads. EGLSurface creation & deletion should ideally be
52 * done on the UI thread and not the RenderThread to avoid stalling the
53 * RenderThread with surface buffer allocation.
54 *
55 * @hide
56 */
57public class ThreadedRenderer extends HardwareRenderer {
58 private static final String LOGTAG = "ThreadedRenderer";
59
John Reckf9be7792014-05-02 18:21:16 -070060 // Keep in sync with DrawFrameTask.h SYNC_* flags
61 // Nothing interesting to report
John Reckcd028f32014-06-24 08:44:29 -070062 private static final int SYNC_OK = 0;
John Reckf9be7792014-05-02 18:21:16 -070063 // Needs a ViewRoot invalidate
John Reckcd028f32014-06-24 08:44:29 -070064 private static final int SYNC_INVALIDATE_REQUIRED = 1 << 0;
John Reckf9be7792014-05-02 18:21:16 -070065
John Reckfe5e7b72014-05-23 17:42:28 -070066 private static final String[] VISUALIZERS = {
67 PROFILE_PROPERTY_VISUALIZE_BARS,
68 };
69
John Reckcec24ae2013-11-05 13:27:50 -080070 private int mWidth, mHeight;
John Reck4f02bf42014-01-03 18:09:17 -080071 private long mNativeProxy;
John Reckf7d9c1d2014-04-09 10:01:03 -070072 private boolean mInitialized = false;
John Reckbc0cc022014-04-11 16:08:14 -070073 private RenderNode mRootNode;
John Reck18f16e62014-05-02 16:46:41 -070074 private Choreographer mChoreographer;
John Reckfe5e7b72014-05-23 17:42:28 -070075 private boolean mProfilingEnabled;
John Reckcec24ae2013-11-05 13:27:50 -080076
John Reckb8802b12014-06-16 15:28:50 -070077 ThreadedRenderer(Context context, boolean translucent) {
John Recke45b1fd2014-04-15 09:50:16 -070078 long rootNodePtr = nCreateRootRenderNode();
79 mRootNode = RenderNode.adopt(rootNodePtr);
John Reckbc0cc022014-04-11 16:08:14 -070080 mRootNode.setClipToBounds(false);
John Recke45b1fd2014-04-15 09:50:16 -070081 mNativeProxy = nCreateProxy(translucent, rootNodePtr);
John Reck18f16e62014-05-02 16:46:41 -070082
John Reck3b202512014-06-23 13:13:08 -070083 AtlasInitializer.sInstance.init(context, mNativeProxy);
84
John Reck18f16e62014-05-02 16:46:41 -070085 // Setup timing
86 mChoreographer = Choreographer.getInstance();
87 nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
John Reckfe5e7b72014-05-23 17:42:28 -070088
89 loadSystemProperties();
John Reckcec24ae2013-11-05 13:27:50 -080090 }
91
92 @Override
93 void destroy(boolean full) {
John Reckf7d9c1d2014-04-09 10:01:03 -070094 mInitialized = false;
95 updateEnabledState(null);
John Reckfae904d2014-04-14 11:01:57 -070096 nDestroyCanvasAndSurface(mNativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -080097 }
98
John Reckf7d9c1d2014-04-09 10:01:03 -070099 private void updateEnabledState(Surface surface) {
100 if (surface == null || !surface.isValid()) {
101 setEnabled(false);
102 } else {
103 setEnabled(mInitialized);
104 }
105 }
106
John Reckcec24ae2013-11-05 13:27:50 -0800107 @Override
108 boolean initialize(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700109 mInitialized = true;
110 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -0800111 return nInitialize(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800112 }
113
114 @Override
115 void updateSurface(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700116 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -0800117 nUpdateSurface(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800118 }
119
120 @Override
John Reckf7d9c1d2014-04-09 10:01:03 -0700121 void pauseSurface(Surface surface) {
122 nPauseSurface(mNativeProxy, surface);
123 }
124
125 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800126 void destroyHardwareResources(View view) {
John Reck4f02bf42014-01-03 18:09:17 -0800127 destroyResources(view);
John Recke1628b72014-05-23 15:11:19 -0700128 nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS);
John Reck4f02bf42014-01-03 18:09:17 -0800129 }
130
131 private static void destroyResources(View view) {
132 view.destroyHardwareResources();
133
134 if (view instanceof ViewGroup) {
135 ViewGroup group = (ViewGroup) view;
136
137 int count = group.getChildCount();
138 for (int i = 0; i < count; i++) {
139 destroyResources(group.getChildAt(i));
140 }
141 }
John Reckcec24ae2013-11-05 13:27:50 -0800142 }
143
144 @Override
145 void invalidate(Surface surface) {
John Reck4f02bf42014-01-03 18:09:17 -0800146 updateSurface(surface);
John Reckcec24ae2013-11-05 13:27:50 -0800147 }
148
149 @Override
John Reck918ad522014-06-27 14:45:25 -0700150 void detachSurfaceTexture(long hardwareLayer) {
151 nDetachSurfaceTexture(mNativeProxy, hardwareLayer);
John Reckcec24ae2013-11-05 13:27:50 -0800152 }
153
154 @Override
Chris Craik797b95b2014-05-20 18:10:25 -0700155 void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) {
John Reckcec24ae2013-11-05 13:27:50 -0800156 mWidth = width;
157 mHeight = height;
John Reckbc0cc022014-04-11 16:08:14 -0700158 mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
Chris Craik797b95b2014-05-20 18:10:25 -0700159 nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius);
John Reckcec24ae2013-11-05 13:27:50 -0800160 }
161
162 @Override
John Reck63a06672014-05-07 13:45:54 -0700163 void setOpaque(boolean opaque) {
164 nSetOpaque(mNativeProxy, opaque);
165 }
166
167 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800168 int getWidth() {
169 return mWidth;
170 }
171
172 @Override
173 int getHeight() {
174 return mHeight;
175 }
176
177 @Override
John Reckfe5e7b72014-05-23 17:42:28 -0700178 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
179 pw.flush();
180 nDumpProfileInfo(mNativeProxy, fd);
John Reckcec24ae2013-11-05 13:27:50 -0800181 }
182
John Reckfe5e7b72014-05-23 17:42:28 -0700183 private static int search(String[] values, String value) {
184 for (int i = 0; i < values.length; i++) {
185 if (values[i].equals(value)) return i;
186 }
187 return -1;
188 }
189
190 private static boolean checkIfProfilingRequested() {
191 String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY);
192 int graphType = search(VISUALIZERS, profiling);
193 return (graphType >= 0) || Boolean.parseBoolean(profiling);
John Reckcec24ae2013-11-05 13:27:50 -0800194 }
195
196 @Override
197 boolean loadSystemProperties() {
John Reckfe5e7b72014-05-23 17:42:28 -0700198 boolean changed = nLoadSystemProperties(mNativeProxy);
199 boolean wantProfiling = checkIfProfilingRequested();
200 if (wantProfiling != mProfilingEnabled) {
201 mProfilingEnabled = wantProfiling;
202 changed = true;
203 }
204 return changed;
John Reckcec24ae2013-11-05 13:27:50 -0800205 }
206
John Reckbc0cc022014-04-11 16:08:14 -0700207 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
John Reckcec24ae2013-11-05 13:27:50 -0800208 view.mPrivateFlags |= View.PFLAG_DRAWN;
209
210 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
211 == View.PFLAG_INVALIDATED;
212 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
213
214 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
John Reckbc0cc022014-04-11 16:08:14 -0700215 HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
John Reck05e85842014-04-23 14:48:28 -0700216 try {
John Reck86faf9e2014-05-19 13:19:07 -0700217 canvas.save();
Alan Viveretted5b2ec42014-05-17 16:34:09 -0700218 callbacks.onHardwarePreDraw(canvas);
Chris Craika7090e02014-06-20 16:01:00 -0700219 canvas.drawRenderNode(view.getDisplayList());
John Reck05e85842014-04-23 14:48:28 -0700220 callbacks.onHardwarePostDraw(canvas);
John Reck86faf9e2014-05-19 13:19:07 -0700221 canvas.restore();
John Reck05e85842014-04-23 14:48:28 -0700222 } finally {
223 mRootNode.end(canvas);
224 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
225 }
John Reckcec24ae2013-11-05 13:27:50 -0800226
227 view.mRecreateDisplayList = false;
John Reckbc0cc022014-04-11 16:08:14 -0700228 }
229
230 @Override
John Recke4267ea2014-06-03 15:53:15 -0700231 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
John Reckbc0cc022014-04-11 16:08:14 -0700232 attachInfo.mIgnoreDirtyState = true;
John Reck18f16e62014-05-02 16:46:41 -0700233 long frameTimeNanos = mChoreographer.getFrameTimeNanos();
John Reck315c3292014-05-09 19:21:04 -0700234 attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
John Reckbc0cc022014-04-11 16:08:14 -0700235
John Reckfe5e7b72014-05-23 17:42:28 -0700236 long recordDuration = 0;
237 if (mProfilingEnabled) {
238 recordDuration = System.nanoTime();
239 }
240
John Reckbc0cc022014-04-11 16:08:14 -0700241 updateRootDisplayList(view, callbacks);
John Reckcec24ae2013-11-05 13:27:50 -0800242
John Reckfe5e7b72014-05-23 17:42:28 -0700243 if (mProfilingEnabled) {
244 recordDuration = System.nanoTime() - recordDuration;
245 }
246
John Reck6313b922014-04-16 18:59:21 -0700247 attachInfo.mIgnoreDirtyState = false;
248
John Reckf9be7792014-05-02 18:21:16 -0700249 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
John Recke4267ea2014-06-03 15:53:15 -0700250 recordDuration, view.getResources().getDisplayMetrics().density);
John Reckf9be7792014-05-02 18:21:16 -0700251 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
252 attachInfo.mViewRootImpl.invalidate();
253 }
John Reckcec24ae2013-11-05 13:27:50 -0800254 }
255
John Reck3b202512014-06-23 13:13:08 -0700256 static void invokeFunctor(long functor, boolean waitForCompletion) {
257 nInvokeFunctor(functor, waitForCompletion);
John Reck0d1f6342014-03-28 20:30:27 -0700258 }
259
260 @Override
John Reck19b6bcf2014-02-14 20:03:38 -0800261 HardwareLayer createTextureLayer() {
262 long layer = nCreateTextureLayer(mNativeProxy);
263 return HardwareLayer.adoptTextureLayer(this, layer);
264 }
265
266 @Override
John Reck19b6bcf2014-02-14 20:03:38 -0800267 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
268 return nCopyLayerInto(mNativeProxy,
269 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
270 }
271
272 @Override
273 void pushLayerUpdate(HardwareLayer layer) {
John Reckd72e0a32014-05-29 18:56:11 -0700274 nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
John Reck19b6bcf2014-02-14 20:03:38 -0800275 }
276
277 @Override
John Reck19b6bcf2014-02-14 20:03:38 -0800278 void onLayerDestroyed(HardwareLayer layer) {
John Reckd72e0a32014-05-29 18:56:11 -0700279 nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
John Reck19b6bcf2014-02-14 20:03:38 -0800280 }
281
282 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800283 void setName(String name) {
John Reckcec24ae2013-11-05 13:27:50 -0800284 }
285
John Reck4f02bf42014-01-03 18:09:17 -0800286 @Override
John Reck28ad7b52014-04-07 16:59:25 -0700287 void fence() {
288 nFence(mNativeProxy);
289 }
290
291 @Override
John Recka5dda642014-05-22 15:43:54 -0700292 public void notifyFramePending() {
293 nNotifyFramePending(mNativeProxy);
294 }
295
296 @Override
John Reck4f02bf42014-01-03 18:09:17 -0800297 protected void finalize() throws Throwable {
298 try {
299 nDeleteProxy(mNativeProxy);
John Reck0ed751d2014-04-08 14:10:17 -0700300 mNativeProxy = 0;
John Reck4f02bf42014-01-03 18:09:17 -0800301 } finally {
302 super.finalize();
John Reckcec24ae2013-11-05 13:27:50 -0800303 }
304 }
305
John Reck84a4c882014-05-30 14:34:03 -0700306 static void startTrimMemory(int level) {
307 // TODO
308 }
309
310 static void endTrimMemory() {
311 // TODO
312 }
313
John Reck66f0be62014-05-13 13:39:31 -0700314 private static class AtlasInitializer {
315 static AtlasInitializer sInstance = new AtlasInitializer();
316
317 private boolean mInitialized = false;
318
319 private AtlasInitializer() {}
320
John Reck3b202512014-06-23 13:13:08 -0700321 synchronized void init(Context context, long renderProxy) {
John Reck66f0be62014-05-13 13:39:31 -0700322 if (mInitialized) return;
323 IBinder binder = ServiceManager.getService("assetatlas");
324 if (binder == null) return;
325
326 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
327 try {
328 if (atlas.isCompatible(android.os.Process.myPpid())) {
329 GraphicBuffer buffer = atlas.getBuffer();
330 if (buffer != null) {
331 long[] map = atlas.getMap();
332 if (map != null) {
John Reckb8802b12014-06-16 15:28:50 -0700333 // TODO Remove after fixing b/15425820
334 validateMap(context, map);
John Reck3b202512014-06-23 13:13:08 -0700335 nSetAtlas(renderProxy, buffer, map);
John Reck66f0be62014-05-13 13:39:31 -0700336 mInitialized = true;
337 }
338 // If IAssetAtlas is not the same class as the IBinder
339 // we are using a remote service and we can safely
340 // destroy the graphic buffer
341 if (atlas.getClass() != binder.getClass()) {
342 buffer.destroy();
343 }
344 }
345 }
346 } catch (RemoteException e) {
347 Log.w(LOG_TAG, "Could not acquire atlas", e);
348 }
349 }
John Reckb8802b12014-06-16 15:28:50 -0700350
351 private static void validateMap(Context context, long[] map) {
352 Log.d("Atlas", "Validating map...");
353 HashSet<Long> preloadedPointers = new HashSet<Long>();
354
355 // We only care about drawables that hold bitmaps
356 final Resources resources = context.getResources();
357 final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
358
359 final int count = drawables.size();
360 for (int i = 0; i < count; i++) {
361 final Bitmap bitmap = drawables.valueAt(i).getBitmap();
362 if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
363 preloadedPointers.add(bitmap.mNativeBitmap);
364 }
365 }
366
367 for (int i = 0; i < map.length; i += 4) {
368 if (!preloadedPointers.contains(map[i])) {
369 Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i]));
370 map[i] = 0;
371 }
372 }
373 }
John Reck66f0be62014-05-13 13:39:31 -0700374 }
375
John Reck84a4c882014-05-30 14:34:03 -0700376 static native void setupShadersDiskCache(String cacheFile);
377
John Reck3b202512014-06-23 13:13:08 -0700378 private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
John Reck4f02bf42014-01-03 18:09:17 -0800379
John Recke45b1fd2014-04-15 09:50:16 -0700380 private static native long nCreateRootRenderNode();
381 private static native long nCreateProxy(boolean translucent, long rootRenderNode);
John Reck4f02bf42014-01-03 18:09:17 -0800382 private static native void nDeleteProxy(long nativeProxy);
383
John Reck18f16e62014-05-02 16:46:41 -0700384 private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
John Recke4280ba2014-05-05 16:39:37 -0700385 private static native boolean nLoadSystemProperties(long nativeProxy);
John Reck18f16e62014-05-02 16:46:41 -0700386
John Reck4f02bf42014-01-03 18:09:17 -0800387 private static native boolean nInitialize(long nativeProxy, Surface window);
388 private static native void nUpdateSurface(long nativeProxy, Surface window);
John Reckf7d9c1d2014-04-09 10:01:03 -0700389 private static native void nPauseSurface(long nativeProxy, Surface window);
Chris Craik797b95b2014-05-20 18:10:25 -0700390 private static native void nSetup(long nativeProxy, int width, int height,
391 float lightX, float lightY, float lightZ, float lightRadius);
John Reck63a06672014-05-07 13:45:54 -0700392 private static native void nSetOpaque(long nativeProxy, boolean opaque);
John Reckfe5e7b72014-05-23 17:42:28 -0700393 private static native int nSyncAndDrawFrame(long nativeProxy,
John Recke4267ea2014-06-03 15:53:15 -0700394 long frameTimeNanos, long recordDuration, float density);
John Reckfae904d2014-04-14 11:01:57 -0700395 private static native void nDestroyCanvasAndSurface(long nativeProxy);
John Reck4f02bf42014-01-03 18:09:17 -0800396
John Reck3b202512014-06-23 13:13:08 -0700397 private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
John Reck19b6bcf2014-02-14 20:03:38 -0800398
399 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
400 private static native long nCreateTextureLayer(long nativeProxy);
401 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
John Reckd72e0a32014-05-29 18:56:11 -0700402 private static native void nPushLayerUpdate(long nativeProxy, long layer);
403 private static native void nCancelLayerUpdate(long nativeProxy, long layer);
John Reck918ad522014-06-27 14:45:25 -0700404 private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
John Reck28ad7b52014-04-07 16:59:25 -0700405
John Recke1628b72014-05-23 15:11:19 -0700406 private static native void nFlushCaches(long nativeProxy, int flushMode);
407
John Reck28ad7b52014-04-07 16:59:25 -0700408 private static native void nFence(long nativeProxy);
John Recka5dda642014-05-22 15:43:54 -0700409 private static native void nNotifyFramePending(long nativeProxy);
John Reckfe5e7b72014-05-23 17:42:28 -0700410
411 private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
John Reckcec24ae2013-11-05 13:27:50 -0800412}