blob: 9c9a939c0a0f0307712d85d140c0dd27bd8718bd [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 Reckcec24ae2013-11-05 13:27:50 -080025import android.os.Trace;
John Reck66f0be62014-05-13 13:39:31 -070026import android.util.Log;
John Reck315c3292014-05-09 19:21:04 -070027import android.util.TimeUtils;
John Reckcec24ae2013-11-05 13:27:50 -080028import android.view.Surface.OutOfResourcesException;
29import android.view.View.AttachInfo;
30
31import java.io.PrintWriter;
John Reckcec24ae2013-11-05 13:27:50 -080032
33/**
34 * Hardware renderer that proxies the rendering to a render thread. Most calls
John Reck4f02bf42014-01-03 18:09:17 -080035 * are currently synchronous.
John Reckcec24ae2013-11-05 13:27:50 -080036 *
37 * The UI thread can block on the RenderThread, but RenderThread must never
38 * block on the UI thread.
39 *
John Reck4f02bf42014-01-03 18:09:17 -080040 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates
41 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed
42 * by the lifecycle of the RenderProxy.
43 *
John Reckcec24ae2013-11-05 13:27:50 -080044 * Note that although currently the EGL context & surfaces are created & managed
45 * by the render thread, the goal is to move that into a shared structure that can
46 * be managed by both threads. EGLSurface creation & deletion should ideally be
47 * done on the UI thread and not the RenderThread to avoid stalling the
48 * RenderThread with surface buffer allocation.
49 *
50 * @hide
51 */
52public class ThreadedRenderer extends HardwareRenderer {
53 private static final String LOGTAG = "ThreadedRenderer";
54
John Recke45b1fd2014-04-15 09:50:16 -070055 private static final Rect NULL_RECT = new Rect();
John Reckcec24ae2013-11-05 13:27:50 -080056
John Reckf9be7792014-05-02 18:21:16 -070057 // Keep in sync with DrawFrameTask.h SYNC_* flags
58 // Nothing interesting to report
59 private static final int SYNC_OK = 0x0;
60 // Needs a ViewRoot invalidate
61 private static final int SYNC_INVALIDATE_REQUIRED = 0x1;
62
John Reckcec24ae2013-11-05 13:27:50 -080063 private int mWidth, mHeight;
John Reck4f02bf42014-01-03 18:09:17 -080064 private long mNativeProxy;
John Reckf7d9c1d2014-04-09 10:01:03 -070065 private boolean mInitialized = false;
John Reckbc0cc022014-04-11 16:08:14 -070066 private RenderNode mRootNode;
John Reck18f16e62014-05-02 16:46:41 -070067 private Choreographer mChoreographer;
John Reckcec24ae2013-11-05 13:27:50 -080068
John Reck3dfe19f2013-12-13 14:25:19 -080069 ThreadedRenderer(boolean translucent) {
John Reck66f0be62014-05-13 13:39:31 -070070 AtlasInitializer.sInstance.init();
71
John Recke45b1fd2014-04-15 09:50:16 -070072 long rootNodePtr = nCreateRootRenderNode();
73 mRootNode = RenderNode.adopt(rootNodePtr);
John Reckbc0cc022014-04-11 16:08:14 -070074 mRootNode.setClipToBounds(false);
John Recke45b1fd2014-04-15 09:50:16 -070075 mNativeProxy = nCreateProxy(translucent, rootNodePtr);
John Reck18f16e62014-05-02 16:46:41 -070076
77 // Setup timing
78 mChoreographer = Choreographer.getInstance();
79 nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
John Reckcec24ae2013-11-05 13:27:50 -080080 }
81
82 @Override
83 void destroy(boolean full) {
John Reckf7d9c1d2014-04-09 10:01:03 -070084 mInitialized = false;
85 updateEnabledState(null);
John Reckfae904d2014-04-14 11:01:57 -070086 nDestroyCanvasAndSurface(mNativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -080087 }
88
John Reckf7d9c1d2014-04-09 10:01:03 -070089 private void updateEnabledState(Surface surface) {
90 if (surface == null || !surface.isValid()) {
91 setEnabled(false);
92 } else {
93 setEnabled(mInitialized);
94 }
95 }
96
John Reckcec24ae2013-11-05 13:27:50 -080097 @Override
98 boolean initialize(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -070099 mInitialized = true;
100 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -0800101 return nInitialize(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800102 }
103
104 @Override
105 void updateSurface(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700106 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -0800107 nUpdateSurface(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800108 }
109
110 @Override
John Reckf7d9c1d2014-04-09 10:01:03 -0700111 void pauseSurface(Surface surface) {
112 nPauseSurface(mNativeProxy, surface);
113 }
114
115 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800116 void destroyHardwareResources(View view) {
John Reck4f02bf42014-01-03 18:09:17 -0800117 destroyResources(view);
John Recke1628b72014-05-23 15:11:19 -0700118 nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS);
John Reck4f02bf42014-01-03 18:09:17 -0800119 }
120
121 private static void destroyResources(View view) {
122 view.destroyHardwareResources();
123
124 if (view instanceof ViewGroup) {
125 ViewGroup group = (ViewGroup) view;
126
127 int count = group.getChildCount();
128 for (int i = 0; i < count; i++) {
129 destroyResources(group.getChildAt(i));
130 }
131 }
John Reckcec24ae2013-11-05 13:27:50 -0800132 }
133
134 @Override
135 void invalidate(Surface surface) {
John Reck4f02bf42014-01-03 18:09:17 -0800136 updateSurface(surface);
John Reckcec24ae2013-11-05 13:27:50 -0800137 }
138
139 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800140 boolean safelyRun(Runnable action) {
John Reckfc53ef272014-02-11 10:40:25 -0800141 nRunWithGlContext(mNativeProxy, action);
142 return true;
John Reckcec24ae2013-11-05 13:27:50 -0800143 }
144
145 @Override
Chris Craik797b95b2014-05-20 18:10:25 -0700146 void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) {
John Reckcec24ae2013-11-05 13:27:50 -0800147 mWidth = width;
148 mHeight = height;
John Reckbc0cc022014-04-11 16:08:14 -0700149 mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
Chris Craik797b95b2014-05-20 18:10:25 -0700150 nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius);
John Reckcec24ae2013-11-05 13:27:50 -0800151 }
152
153 @Override
John Reck63a06672014-05-07 13:45:54 -0700154 void setOpaque(boolean opaque) {
155 nSetOpaque(mNativeProxy, opaque);
156 }
157
158 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800159 int getWidth() {
160 return mWidth;
161 }
162
163 @Override
164 int getHeight() {
165 return mHeight;
166 }
167
168 @Override
169 void dumpGfxInfo(PrintWriter pw) {
170 // TODO Auto-generated method stub
171 }
172
173 @Override
174 long getFrameCount() {
175 // TODO Auto-generated method stub
176 return 0;
177 }
178
179 @Override
180 boolean loadSystemProperties() {
John Recke4280ba2014-05-05 16:39:37 -0700181 return nLoadSystemProperties(mNativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -0800182 }
183
John Reckbc0cc022014-04-11 16:08:14 -0700184 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
John Reckcec24ae2013-11-05 13:27:50 -0800185 view.mPrivateFlags |= View.PFLAG_DRAWN;
186
187 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
188 == View.PFLAG_INVALIDATED;
189 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
190
191 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
John Reckbc0cc022014-04-11 16:08:14 -0700192 HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
John Reck05e85842014-04-23 14:48:28 -0700193 try {
John Reck86faf9e2014-05-19 13:19:07 -0700194 canvas.save();
Alan Viveretted5b2ec42014-05-17 16:34:09 -0700195 callbacks.onHardwarePreDraw(canvas);
John Reck05e85842014-04-23 14:48:28 -0700196 canvas.drawDisplayList(view.getDisplayList());
197 callbacks.onHardwarePostDraw(canvas);
John Reck86faf9e2014-05-19 13:19:07 -0700198 canvas.restore();
John Reck05e85842014-04-23 14:48:28 -0700199 } finally {
200 mRootNode.end(canvas);
201 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
202 }
John Reckcec24ae2013-11-05 13:27:50 -0800203
204 view.mRecreateDisplayList = false;
John Reckbc0cc022014-04-11 16:08:14 -0700205 }
206
207 @Override
208 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
209 attachInfo.mIgnoreDirtyState = true;
John Reck18f16e62014-05-02 16:46:41 -0700210 long frameTimeNanos = mChoreographer.getFrameTimeNanos();
John Reck315c3292014-05-09 19:21:04 -0700211 attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
John Reckbc0cc022014-04-11 16:08:14 -0700212
213 updateRootDisplayList(view, callbacks);
John Reckcec24ae2013-11-05 13:27:50 -0800214
John Reck6313b922014-04-16 18:59:21 -0700215 attachInfo.mIgnoreDirtyState = false;
216
John Reck4f02bf42014-01-03 18:09:17 -0800217 if (dirty == null) {
218 dirty = NULL_RECT;
219 }
John Reckf9be7792014-05-02 18:21:16 -0700220 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
John Reck18f16e62014-05-02 16:46:41 -0700221 dirty.left, dirty.top, dirty.right, dirty.bottom);
John Reckf9be7792014-05-02 18:21:16 -0700222 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
223 attachInfo.mViewRootImpl.invalidate();
224 }
John Reckcec24ae2013-11-05 13:27:50 -0800225 }
226
227 @Override
Bo Liuae738a72014-04-27 16:22:04 -0700228 void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck0d1f6342014-03-28 20:30:27 -0700229 nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
230 }
231
232 @Override
John Reck19b6bcf2014-02-14 20:03:38 -0800233 HardwareLayer createDisplayListLayer(int width, int height) {
234 long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
235 return HardwareLayer.adoptDisplayListLayer(this, layer);
236 }
237
238 @Override
239 HardwareLayer createTextureLayer() {
240 long layer = nCreateTextureLayer(mNativeProxy);
241 return HardwareLayer.adoptTextureLayer(this, layer);
242 }
243
244 @Override
245 SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
246 final SurfaceTexture[] ret = new SurfaceTexture[1];
247 nRunWithGlContext(mNativeProxy, new Runnable() {
248 @Override
249 public void run() {
250 ret[0] = layer.createSurfaceTexture();
251 }
252 });
253 return ret[0];
254 }
255
256 @Override
257 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
258 return nCopyLayerInto(mNativeProxy,
259 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
260 }
261
262 @Override
263 void pushLayerUpdate(HardwareLayer layer) {
264 // TODO: Remove this, it's not needed outside of GLRenderer
265 }
266
267 @Override
268 void onLayerCreated(HardwareLayer layer) {
269 // TODO: Is this actually useful?
270 }
271
272 @Override
273 void flushLayerUpdates() {
274 // TODO: Figure out what this should do or remove it
275 }
276
277 @Override
278 void onLayerDestroyed(HardwareLayer layer) {
279 nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
280 }
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 Reck66f0be62014-05-13 13:39:31 -0700306 private static class AtlasInitializer {
307 static AtlasInitializer sInstance = new AtlasInitializer();
308
309 private boolean mInitialized = false;
310
311 private AtlasInitializer() {}
312
313 synchronized void init() {
314 if (mInitialized) return;
315 IBinder binder = ServiceManager.getService("assetatlas");
316 if (binder == null) return;
317
318 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
319 try {
320 if (atlas.isCompatible(android.os.Process.myPpid())) {
321 GraphicBuffer buffer = atlas.getBuffer();
322 if (buffer != null) {
323 long[] map = atlas.getMap();
324 if (map != null) {
325 nSetAtlas(buffer, map);
326 mInitialized = true;
327 }
328 // If IAssetAtlas is not the same class as the IBinder
329 // we are using a remote service and we can safely
330 // destroy the graphic buffer
331 if (atlas.getClass() != binder.getClass()) {
332 buffer.destroy();
333 }
334 }
335 }
336 } catch (RemoteException e) {
337 Log.w(LOG_TAG, "Could not acquire atlas", e);
338 }
339 }
340 }
341
342 private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
John Reck4f02bf42014-01-03 18:09:17 -0800343
John Recke45b1fd2014-04-15 09:50:16 -0700344 private static native long nCreateRootRenderNode();
345 private static native long nCreateProxy(boolean translucent, long rootRenderNode);
John Reck4f02bf42014-01-03 18:09:17 -0800346 private static native void nDeleteProxy(long nativeProxy);
347
John Reck18f16e62014-05-02 16:46:41 -0700348 private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
John Recke4280ba2014-05-05 16:39:37 -0700349 private static native boolean nLoadSystemProperties(long nativeProxy);
John Reck18f16e62014-05-02 16:46:41 -0700350
John Reck4f02bf42014-01-03 18:09:17 -0800351 private static native boolean nInitialize(long nativeProxy, Surface window);
352 private static native void nUpdateSurface(long nativeProxy, Surface window);
John Reckf7d9c1d2014-04-09 10:01:03 -0700353 private static native void nPauseSurface(long nativeProxy, Surface window);
Chris Craik797b95b2014-05-20 18:10:25 -0700354 private static native void nSetup(long nativeProxy, int width, int height,
355 float lightX, float lightY, float lightZ, float lightRadius);
John Reck63a06672014-05-07 13:45:54 -0700356 private static native void nSetOpaque(long nativeProxy, boolean opaque);
John Reckf9be7792014-05-02 18:21:16 -0700357 private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
John Reck4f02bf42014-01-03 18:09:17 -0800358 int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
John Reckfc53ef272014-02-11 10:40:25 -0800359 private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
John Reckfae904d2014-04-14 11:01:57 -0700360 private static native void nDestroyCanvasAndSurface(long nativeProxy);
John Reck4f02bf42014-01-03 18:09:17 -0800361
John Reck0d1f6342014-03-28 20:30:27 -0700362 private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
John Reck19b6bcf2014-02-14 20:03:38 -0800363
364 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
365 private static native long nCreateTextureLayer(long nativeProxy);
366 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
367 private static native void nDestroyLayer(long nativeProxy, long layer);
John Reck28ad7b52014-04-07 16:59:25 -0700368
John Recke1628b72014-05-23 15:11:19 -0700369 private static native void nFlushCaches(long nativeProxy, int flushMode);
370
John Reck28ad7b52014-04-07 16:59:25 -0700371 private static native void nFence(long nativeProxy);
John Recka5dda642014-05-22 15:43:54 -0700372 private static native void nNotifyFramePending(long nativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -0800373}