blob: 11db9966cdb768f4508b63b189bb180fb99cfe2c [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 Reck04fc5832014-02-05 16:38:25 -080019import android.graphics.Bitmap;
John Reckcec24ae2013-11-05 13:27:50 -080020import android.graphics.Rect;
21import android.graphics.SurfaceTexture;
John Reck66f0be62014-05-13 13:39:31 -070022import android.os.IBinder;
23import android.os.RemoteException;
24import android.os.ServiceManager;
John Reckfe5e7b72014-05-23 17:42:28 -070025import android.os.SystemProperties;
John Reckcec24ae2013-11-05 13:27:50 -080026import android.os.Trace;
John Reck66f0be62014-05-13 13:39:31 -070027import android.util.Log;
John Reck315c3292014-05-09 19:21:04 -070028import android.util.TimeUtils;
John Reckcec24ae2013-11-05 13:27:50 -080029import android.view.Surface.OutOfResourcesException;
30import android.view.View.AttachInfo;
31
John Reckfe5e7b72014-05-23 17:42:28 -070032import java.io.FileDescriptor;
John Reckcec24ae2013-11-05 13:27:50 -080033import java.io.PrintWriter;
John Reckcec24ae2013-11-05 13:27:50 -080034
35/**
36 * Hardware renderer that proxies the rendering to a render thread. Most calls
John Reck4f02bf42014-01-03 18:09:17 -080037 * are currently synchronous.
John Reckcec24ae2013-11-05 13:27:50 -080038 *
39 * The UI thread can block on the RenderThread, but RenderThread must never
40 * block on the UI thread.
41 *
John Reck4f02bf42014-01-03 18:09:17 -080042 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates
43 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed
44 * by the lifecycle of the RenderProxy.
45 *
John Reckcec24ae2013-11-05 13:27:50 -080046 * Note that although currently the EGL context & surfaces are created & managed
47 * by the render thread, the goal is to move that into a shared structure that can
48 * be managed by both threads. EGLSurface creation & deletion should ideally be
49 * done on the UI thread and not the RenderThread to avoid stalling the
50 * RenderThread with surface buffer allocation.
51 *
52 * @hide
53 */
54public class ThreadedRenderer extends HardwareRenderer {
55 private static final String LOGTAG = "ThreadedRenderer";
56
John Recke45b1fd2014-04-15 09:50:16 -070057 private static final Rect NULL_RECT = new Rect();
John Reckcec24ae2013-11-05 13:27:50 -080058
John Reckf9be7792014-05-02 18:21:16 -070059 // Keep in sync with DrawFrameTask.h SYNC_* flags
60 // Nothing interesting to report
61 private static final int SYNC_OK = 0x0;
62 // Needs a ViewRoot invalidate
63 private static final int SYNC_INVALIDATE_REQUIRED = 0x1;
64
John Reckfe5e7b72014-05-23 17:42:28 -070065 private static final String[] VISUALIZERS = {
66 PROFILE_PROPERTY_VISUALIZE_BARS,
67 };
68
John Reckcec24ae2013-11-05 13:27:50 -080069 private int mWidth, mHeight;
John Reck4f02bf42014-01-03 18:09:17 -080070 private long mNativeProxy;
John Reckf7d9c1d2014-04-09 10:01:03 -070071 private boolean mInitialized = false;
John Reckbc0cc022014-04-11 16:08:14 -070072 private RenderNode mRootNode;
John Reck18f16e62014-05-02 16:46:41 -070073 private Choreographer mChoreographer;
John Reckfe5e7b72014-05-23 17:42:28 -070074 private boolean mProfilingEnabled;
John Reckcec24ae2013-11-05 13:27:50 -080075
John Reck3dfe19f2013-12-13 14:25:19 -080076 ThreadedRenderer(boolean translucent) {
John Reck66f0be62014-05-13 13:39:31 -070077 AtlasInitializer.sInstance.init();
78
John Recke45b1fd2014-04-15 09:50:16 -070079 long rootNodePtr = nCreateRootRenderNode();
80 mRootNode = RenderNode.adopt(rootNodePtr);
John Reckbc0cc022014-04-11 16:08:14 -070081 mRootNode.setClipToBounds(false);
John Recke45b1fd2014-04-15 09:50:16 -070082 mNativeProxy = nCreateProxy(translucent, rootNodePtr);
John Reck18f16e62014-05-02 16:46:41 -070083
84 // Setup timing
85 mChoreographer = Choreographer.getInstance();
86 nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
John Reckfe5e7b72014-05-23 17:42:28 -070087
88 loadSystemProperties();
John Reckcec24ae2013-11-05 13:27:50 -080089 }
90
91 @Override
92 void destroy(boolean full) {
John Reckf7d9c1d2014-04-09 10:01:03 -070093 mInitialized = false;
94 updateEnabledState(null);
John Reckfae904d2014-04-14 11:01:57 -070095 nDestroyCanvasAndSurface(mNativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -080096 }
97
John Reckf7d9c1d2014-04-09 10:01:03 -070098 private void updateEnabledState(Surface surface) {
99 if (surface == null || !surface.isValid()) {
100 setEnabled(false);
101 } else {
102 setEnabled(mInitialized);
103 }
104 }
105
John Reckcec24ae2013-11-05 13:27:50 -0800106 @Override
107 boolean initialize(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700108 mInitialized = true;
109 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -0800110 return nInitialize(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800111 }
112
113 @Override
114 void updateSurface(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700115 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -0800116 nUpdateSurface(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800117 }
118
119 @Override
John Reckf7d9c1d2014-04-09 10:01:03 -0700120 void pauseSurface(Surface surface) {
121 nPauseSurface(mNativeProxy, surface);
122 }
123
124 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800125 void destroyHardwareResources(View view) {
John Reck4f02bf42014-01-03 18:09:17 -0800126 destroyResources(view);
John Recke1628b72014-05-23 15:11:19 -0700127 nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS);
John Reck4f02bf42014-01-03 18:09:17 -0800128 }
129
130 private static void destroyResources(View view) {
131 view.destroyHardwareResources();
132
133 if (view instanceof ViewGroup) {
134 ViewGroup group = (ViewGroup) view;
135
136 int count = group.getChildCount();
137 for (int i = 0; i < count; i++) {
138 destroyResources(group.getChildAt(i));
139 }
140 }
John Reckcec24ae2013-11-05 13:27:50 -0800141 }
142
143 @Override
144 void invalidate(Surface surface) {
John Reck4f02bf42014-01-03 18:09:17 -0800145 updateSurface(surface);
John Reckcec24ae2013-11-05 13:27:50 -0800146 }
147
148 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800149 boolean safelyRun(Runnable action) {
John Reckfc53ef272014-02-11 10:40:25 -0800150 nRunWithGlContext(mNativeProxy, action);
151 return true;
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);
John Reck05e85842014-04-23 14:48:28 -0700219 canvas.drawDisplayList(view.getDisplayList());
220 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
231 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
232 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 Reck4f02bf42014-01-03 18:09:17 -0800249 if (dirty == null) {
250 dirty = NULL_RECT;
251 }
John Reckf9be7792014-05-02 18:21:16 -0700252 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
John Reckfe5e7b72014-05-23 17:42:28 -0700253 recordDuration, view.getResources().getDisplayMetrics().density,
John Reck18f16e62014-05-02 16:46:41 -0700254 dirty.left, dirty.top, dirty.right, dirty.bottom);
John Reckf9be7792014-05-02 18:21:16 -0700255 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
256 attachInfo.mViewRootImpl.invalidate();
257 }
John Reckcec24ae2013-11-05 13:27:50 -0800258 }
259
260 @Override
Bo Liuae738a72014-04-27 16:22:04 -0700261 void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck0d1f6342014-03-28 20:30:27 -0700262 nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
263 }
264
265 @Override
John Reck19b6bcf2014-02-14 20:03:38 -0800266 HardwareLayer createDisplayListLayer(int width, int height) {
267 long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
268 return HardwareLayer.adoptDisplayListLayer(this, layer);
269 }
270
271 @Override
272 HardwareLayer createTextureLayer() {
273 long layer = nCreateTextureLayer(mNativeProxy);
274 return HardwareLayer.adoptTextureLayer(this, layer);
275 }
276
277 @Override
278 SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
279 final SurfaceTexture[] ret = new SurfaceTexture[1];
280 nRunWithGlContext(mNativeProxy, new Runnable() {
281 @Override
282 public void run() {
283 ret[0] = layer.createSurfaceTexture();
284 }
285 });
286 return ret[0];
287 }
288
289 @Override
290 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
291 return nCopyLayerInto(mNativeProxy,
292 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
293 }
294
295 @Override
296 void pushLayerUpdate(HardwareLayer layer) {
John Reckd72e0a32014-05-29 18:56:11 -0700297 nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
John Reck19b6bcf2014-02-14 20:03:38 -0800298 }
299
300 @Override
301 void flushLayerUpdates() {
302 // TODO: Figure out what this should do or remove it
303 }
304
305 @Override
306 void onLayerDestroyed(HardwareLayer layer) {
John Reckd72e0a32014-05-29 18:56:11 -0700307 nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
John Reck19b6bcf2014-02-14 20:03:38 -0800308 }
309
310 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800311 void setName(String name) {
John Reckcec24ae2013-11-05 13:27:50 -0800312 }
313
John Reck4f02bf42014-01-03 18:09:17 -0800314 @Override
John Reck28ad7b52014-04-07 16:59:25 -0700315 void fence() {
316 nFence(mNativeProxy);
317 }
318
319 @Override
John Recka5dda642014-05-22 15:43:54 -0700320 public void notifyFramePending() {
321 nNotifyFramePending(mNativeProxy);
322 }
323
324 @Override
John Reck4f02bf42014-01-03 18:09:17 -0800325 protected void finalize() throws Throwable {
326 try {
327 nDeleteProxy(mNativeProxy);
John Reck0ed751d2014-04-08 14:10:17 -0700328 mNativeProxy = 0;
John Reck4f02bf42014-01-03 18:09:17 -0800329 } finally {
330 super.finalize();
John Reckcec24ae2013-11-05 13:27:50 -0800331 }
332 }
333
John Reck66f0be62014-05-13 13:39:31 -0700334 private static class AtlasInitializer {
335 static AtlasInitializer sInstance = new AtlasInitializer();
336
337 private boolean mInitialized = false;
338
339 private AtlasInitializer() {}
340
341 synchronized void init() {
342 if (mInitialized) return;
343 IBinder binder = ServiceManager.getService("assetatlas");
344 if (binder == null) return;
345
346 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
347 try {
348 if (atlas.isCompatible(android.os.Process.myPpid())) {
349 GraphicBuffer buffer = atlas.getBuffer();
350 if (buffer != null) {
351 long[] map = atlas.getMap();
352 if (map != null) {
353 nSetAtlas(buffer, map);
354 mInitialized = true;
355 }
356 // If IAssetAtlas is not the same class as the IBinder
357 // we are using a remote service and we can safely
358 // destroy the graphic buffer
359 if (atlas.getClass() != binder.getClass()) {
360 buffer.destroy();
361 }
362 }
363 }
364 } catch (RemoteException e) {
365 Log.w(LOG_TAG, "Could not acquire atlas", e);
366 }
367 }
368 }
369
370 private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
John Reck4f02bf42014-01-03 18:09:17 -0800371
John Recke45b1fd2014-04-15 09:50:16 -0700372 private static native long nCreateRootRenderNode();
373 private static native long nCreateProxy(boolean translucent, long rootRenderNode);
John Reck4f02bf42014-01-03 18:09:17 -0800374 private static native void nDeleteProxy(long nativeProxy);
375
John Reck18f16e62014-05-02 16:46:41 -0700376 private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
John Recke4280ba2014-05-05 16:39:37 -0700377 private static native boolean nLoadSystemProperties(long nativeProxy);
John Reck18f16e62014-05-02 16:46:41 -0700378
John Reck4f02bf42014-01-03 18:09:17 -0800379 private static native boolean nInitialize(long nativeProxy, Surface window);
380 private static native void nUpdateSurface(long nativeProxy, Surface window);
John Reckf7d9c1d2014-04-09 10:01:03 -0700381 private static native void nPauseSurface(long nativeProxy, Surface window);
Chris Craik797b95b2014-05-20 18:10:25 -0700382 private static native void nSetup(long nativeProxy, int width, int height,
383 float lightX, float lightY, float lightZ, float lightRadius);
John Reck63a06672014-05-07 13:45:54 -0700384 private static native void nSetOpaque(long nativeProxy, boolean opaque);
John Reckfe5e7b72014-05-23 17:42:28 -0700385 private static native int nSyncAndDrawFrame(long nativeProxy,
386 long frameTimeNanos, long recordDuration, float density,
John Reck4f02bf42014-01-03 18:09:17 -0800387 int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
John Reckfc53ef272014-02-11 10:40:25 -0800388 private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
John Reckfae904d2014-04-14 11:01:57 -0700389 private static native void nDestroyCanvasAndSurface(long nativeProxy);
John Reck4f02bf42014-01-03 18:09:17 -0800390
John Reck0d1f6342014-03-28 20:30:27 -0700391 private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
John Reck19b6bcf2014-02-14 20:03:38 -0800392
393 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
394 private static native long nCreateTextureLayer(long nativeProxy);
395 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
John Reckd72e0a32014-05-29 18:56:11 -0700396 private static native void nPushLayerUpdate(long nativeProxy, long layer);
397 private static native void nCancelLayerUpdate(long nativeProxy, long layer);
John Reck28ad7b52014-04-07 16:59:25 -0700398
John Recke1628b72014-05-23 15:11:19 -0700399 private static native void nFlushCaches(long nativeProxy, int flushMode);
400
John Reck28ad7b52014-04-07 16:59:25 -0700401 private static native void nFence(long nativeProxy);
John Recka5dda642014-05-22 15:43:54 -0700402 private static native void nNotifyFramePending(long nativeProxy);
John Reckfe5e7b72014-05-23 17:42:28 -0700403
404 private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
John Reckcec24ae2013-11-05 13:27:50 -0800405}