ThreadedRenderer.java revision e1628b7c6fc3822fa83cf02028ce8ad67abb0afe
1/*
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
19import android.graphics.Bitmap;
20import android.graphics.Rect;
21import android.graphics.SurfaceTexture;
22import android.os.IBinder;
23import android.os.RemoteException;
24import android.os.ServiceManager;
25import android.os.Trace;
26import android.util.Log;
27import android.util.TimeUtils;
28import android.view.Surface.OutOfResourcesException;
29import android.view.View.AttachInfo;
30
31import java.io.PrintWriter;
32
33/**
34 * Hardware renderer that proxies the rendering to a render thread. Most calls
35 * are currently synchronous.
36 *
37 * The UI thread can block on the RenderThread, but RenderThread must never
38 * block on the UI thread.
39 *
40 * 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 *
44 * 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
55    private static final Rect NULL_RECT = new Rect();
56
57    // 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
63    private int mWidth, mHeight;
64    private long mNativeProxy;
65    private boolean mInitialized = false;
66    private RenderNode mRootNode;
67    private Choreographer mChoreographer;
68
69    ThreadedRenderer(boolean translucent) {
70        AtlasInitializer.sInstance.init();
71
72        long rootNodePtr = nCreateRootRenderNode();
73        mRootNode = RenderNode.adopt(rootNodePtr);
74        mRootNode.setClipToBounds(false);
75        mNativeProxy = nCreateProxy(translucent, rootNodePtr);
76
77        // Setup timing
78        mChoreographer = Choreographer.getInstance();
79        nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
80    }
81
82    @Override
83    void destroy(boolean full) {
84        mInitialized = false;
85        updateEnabledState(null);
86        nDestroyCanvasAndSurface(mNativeProxy);
87    }
88
89    private void updateEnabledState(Surface surface) {
90        if (surface == null || !surface.isValid()) {
91            setEnabled(false);
92        } else {
93            setEnabled(mInitialized);
94        }
95    }
96
97    @Override
98    boolean initialize(Surface surface) throws OutOfResourcesException {
99        mInitialized = true;
100        updateEnabledState(surface);
101        return nInitialize(mNativeProxy, surface);
102    }
103
104    @Override
105    void updateSurface(Surface surface) throws OutOfResourcesException {
106        updateEnabledState(surface);
107        nUpdateSurface(mNativeProxy, surface);
108    }
109
110    @Override
111    void pauseSurface(Surface surface) {
112        nPauseSurface(mNativeProxy, surface);
113    }
114
115    @Override
116    void destroyHardwareResources(View view) {
117        destroyResources(view);
118        nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS);
119    }
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        }
132    }
133
134    @Override
135    void invalidate(Surface surface) {
136        updateSurface(surface);
137    }
138
139    @Override
140    boolean safelyRun(Runnable action) {
141        nRunWithGlContext(mNativeProxy, action);
142        return true;
143    }
144
145    @Override
146    void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) {
147        mWidth = width;
148        mHeight = height;
149        mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
150        nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius);
151    }
152
153    @Override
154    void setOpaque(boolean opaque) {
155        nSetOpaque(mNativeProxy, opaque);
156    }
157
158    @Override
159    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() {
181        return nLoadSystemProperties(mNativeProxy);
182    }
183
184    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
185        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");
192        HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
193        try {
194            canvas.save();
195            callbacks.onHardwarePreDraw(canvas);
196            canvas.drawDisplayList(view.getDisplayList());
197            callbacks.onHardwarePostDraw(canvas);
198            canvas.restore();
199        } finally {
200            mRootNode.end(canvas);
201            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
202        }
203
204        view.mRecreateDisplayList = false;
205    }
206
207    @Override
208    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
209        attachInfo.mIgnoreDirtyState = true;
210        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
211        attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
212
213        updateRootDisplayList(view, callbacks);
214
215        attachInfo.mIgnoreDirtyState = false;
216
217        if (dirty == null) {
218            dirty = NULL_RECT;
219        }
220        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
221                dirty.left, dirty.top, dirty.right, dirty.bottom);
222        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
223            attachInfo.mViewRootImpl.invalidate();
224        }
225    }
226
227    @Override
228    void invokeFunctor(long functor, boolean waitForCompletion) {
229        nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
230    }
231
232    @Override
233    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
283    void setName(String name) {
284    }
285
286    @Override
287    void fence() {
288        nFence(mNativeProxy);
289    }
290
291    @Override
292    public void notifyFramePending() {
293        nNotifyFramePending(mNativeProxy);
294    }
295
296    @Override
297    protected void finalize() throws Throwable {
298        try {
299            nDeleteProxy(mNativeProxy);
300            mNativeProxy = 0;
301        } finally {
302            super.finalize();
303        }
304    }
305
306    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);
343
344    private static native long nCreateRootRenderNode();
345    private static native long nCreateProxy(boolean translucent, long rootRenderNode);
346    private static native void nDeleteProxy(long nativeProxy);
347
348    private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
349    private static native boolean nLoadSystemProperties(long nativeProxy);
350
351    private static native boolean nInitialize(long nativeProxy, Surface window);
352    private static native void nUpdateSurface(long nativeProxy, Surface window);
353    private static native void nPauseSurface(long nativeProxy, Surface window);
354    private static native void nSetup(long nativeProxy, int width, int height,
355            float lightX, float lightY, float lightZ, float lightRadius);
356    private static native void nSetOpaque(long nativeProxy, boolean opaque);
357    private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
358            int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
359    private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
360    private static native void nDestroyCanvasAndSurface(long nativeProxy);
361
362    private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
363
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);
368
369    private static native void nFlushCaches(long nativeProxy, int flushMode);
370
371    private static native void nFence(long nativeProxy);
372    private static native void nNotifyFramePending(long nativeProxy);
373}
374