ThreadedRenderer.java revision 86faf9ec3edc24a9d04548e151bca3a2510396a4
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 * TODO: Make draw() async.
37 * TODO: Figure out how to share the DisplayList between two threads (global lock?)
38 *
39 * The UI thread can block on the RenderThread, but RenderThread must never
40 * block on the UI thread.
41 *
42 * 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 *
46 * 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
57    private static final Rect NULL_RECT = new Rect();
58
59    // 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
65    private int mWidth, mHeight;
66    private long mNativeProxy;
67    private boolean mInitialized = false;
68    private RenderNode mRootNode;
69    private Choreographer mChoreographer;
70
71    ThreadedRenderer(boolean translucent) {
72        AtlasInitializer.sInstance.init();
73
74        long rootNodePtr = nCreateRootRenderNode();
75        mRootNode = RenderNode.adopt(rootNodePtr);
76        mRootNode.setClipToBounds(false);
77        mNativeProxy = nCreateProxy(translucent, rootNodePtr);
78
79        // Setup timing
80        mChoreographer = Choreographer.getInstance();
81        nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
82    }
83
84    @Override
85    void destroy(boolean full) {
86        mInitialized = false;
87        updateEnabledState(null);
88        nDestroyCanvasAndSurface(mNativeProxy);
89    }
90
91    private void updateEnabledState(Surface surface) {
92        if (surface == null || !surface.isValid()) {
93            setEnabled(false);
94        } else {
95            setEnabled(mInitialized);
96        }
97    }
98
99    @Override
100    boolean initialize(Surface surface) throws OutOfResourcesException {
101        mInitialized = true;
102        updateEnabledState(surface);
103        return nInitialize(mNativeProxy, surface);
104    }
105
106    @Override
107    void updateSurface(Surface surface) throws OutOfResourcesException {
108        updateEnabledState(surface);
109        nUpdateSurface(mNativeProxy, surface);
110    }
111
112    @Override
113    void pauseSurface(Surface surface) {
114        nPauseSurface(mNativeProxy, surface);
115    }
116
117    @Override
118    void destroyHardwareResources(View view) {
119        destroyResources(view);
120        // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
121    }
122
123    private static void destroyResources(View view) {
124        view.destroyHardwareResources();
125
126        if (view instanceof ViewGroup) {
127            ViewGroup group = (ViewGroup) view;
128
129            int count = group.getChildCount();
130            for (int i = 0; i < count; i++) {
131                destroyResources(group.getChildAt(i));
132            }
133        }
134    }
135
136    @Override
137    void invalidate(Surface surface) {
138        updateSurface(surface);
139    }
140
141    @Override
142    boolean safelyRun(Runnable action) {
143        nRunWithGlContext(mNativeProxy, action);
144        return true;
145    }
146
147    @Override
148    void setup(int width, int height) {
149        mWidth = width;
150        mHeight = height;
151        mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
152        nSetup(mNativeProxy, width, height);
153    }
154
155    @Override
156    void setOpaque(boolean opaque) {
157        nSetOpaque(mNativeProxy, opaque);
158    }
159
160    @Override
161    int getWidth() {
162        return mWidth;
163    }
164
165    @Override
166    int getHeight() {
167        return mHeight;
168    }
169
170    @Override
171    void dumpGfxInfo(PrintWriter pw) {
172        // TODO Auto-generated method stub
173    }
174
175    @Override
176    long getFrameCount() {
177        // TODO Auto-generated method stub
178        return 0;
179    }
180
181    @Override
182    boolean loadSystemProperties() {
183        return nLoadSystemProperties(mNativeProxy);
184    }
185
186    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
187        view.mPrivateFlags |= View.PFLAG_DRAWN;
188
189        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
190                == View.PFLAG_INVALIDATED;
191        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
192
193        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
194        HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
195        try {
196            canvas.save();
197            callbacks.onHardwarePreDraw(canvas);
198            canvas.drawDisplayList(view.getDisplayList());
199            callbacks.onHardwarePostDraw(canvas);
200            canvas.restore();
201        } finally {
202            mRootNode.end(canvas);
203            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
204        }
205
206        view.mRecreateDisplayList = false;
207    }
208
209    @Override
210    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
211        attachInfo.mIgnoreDirtyState = true;
212        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
213        attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
214
215        updateRootDisplayList(view, callbacks);
216
217        attachInfo.mIgnoreDirtyState = false;
218
219        if (dirty == null) {
220            dirty = NULL_RECT;
221        }
222        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
223                dirty.left, dirty.top, dirty.right, dirty.bottom);
224        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
225            attachInfo.mViewRootImpl.invalidate();
226        }
227    }
228
229    @Override
230    void invokeFunctor(long functor, boolean waitForCompletion) {
231        nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
232    }
233
234    @Override
235    HardwareLayer createDisplayListLayer(int width, int height) {
236        long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
237        return HardwareLayer.adoptDisplayListLayer(this, layer);
238    }
239
240    @Override
241    HardwareLayer createTextureLayer() {
242        long layer = nCreateTextureLayer(mNativeProxy);
243        return HardwareLayer.adoptTextureLayer(this, layer);
244    }
245
246    @Override
247    SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
248        final SurfaceTexture[] ret = new SurfaceTexture[1];
249        nRunWithGlContext(mNativeProxy, new Runnable() {
250            @Override
251            public void run() {
252                ret[0] = layer.createSurfaceTexture();
253            }
254        });
255        return ret[0];
256    }
257
258    @Override
259    boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
260        return nCopyLayerInto(mNativeProxy,
261                layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
262    }
263
264    @Override
265    void pushLayerUpdate(HardwareLayer layer) {
266        // TODO: Remove this, it's not needed outside of GLRenderer
267    }
268
269    @Override
270    void onLayerCreated(HardwareLayer layer) {
271        // TODO: Is this actually useful?
272    }
273
274    @Override
275    void flushLayerUpdates() {
276        // TODO: Figure out what this should do or remove it
277    }
278
279    @Override
280    void onLayerDestroyed(HardwareLayer layer) {
281        nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
282    }
283
284    @Override
285    void setName(String name) {
286    }
287
288    @Override
289    void fence() {
290        nFence(mNativeProxy);
291    }
292
293    @Override
294    protected void finalize() throws Throwable {
295        try {
296            nDeleteProxy(mNativeProxy);
297            mNativeProxy = 0;
298        } finally {
299            super.finalize();
300        }
301    }
302
303    private static class AtlasInitializer {
304        static AtlasInitializer sInstance = new AtlasInitializer();
305
306        private boolean mInitialized = false;
307
308        private AtlasInitializer() {}
309
310        synchronized void init() {
311            if (mInitialized) return;
312            IBinder binder = ServiceManager.getService("assetatlas");
313            if (binder == null) return;
314
315            IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
316            try {
317                if (atlas.isCompatible(android.os.Process.myPpid())) {
318                    GraphicBuffer buffer = atlas.getBuffer();
319                    if (buffer != null) {
320                        long[] map = atlas.getMap();
321                        if (map != null) {
322                            nSetAtlas(buffer, map);
323                            mInitialized = true;
324                        }
325                        // If IAssetAtlas is not the same class as the IBinder
326                        // we are using a remote service and we can safely
327                        // destroy the graphic buffer
328                        if (atlas.getClass() != binder.getClass()) {
329                            buffer.destroy();
330                        }
331                    }
332                }
333            } catch (RemoteException e) {
334                Log.w(LOG_TAG, "Could not acquire atlas", e);
335            }
336        }
337    }
338
339    private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
340
341    private static native long nCreateRootRenderNode();
342    private static native long nCreateProxy(boolean translucent, long rootRenderNode);
343    private static native void nDeleteProxy(long nativeProxy);
344
345    private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
346    private static native boolean nLoadSystemProperties(long nativeProxy);
347
348    private static native boolean nInitialize(long nativeProxy, Surface window);
349    private static native void nUpdateSurface(long nativeProxy, Surface window);
350    private static native void nPauseSurface(long nativeProxy, Surface window);
351    private static native void nSetup(long nativeProxy, int width, int height);
352    private static native void nSetOpaque(long nativeProxy, boolean opaque);
353    private static native void nSetDisplayListData(long nativeProxy, long displayList,
354            long newData);
355    private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
356            int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
357    private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
358    private static native void nDestroyCanvasAndSurface(long nativeProxy);
359
360    private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
361
362    private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
363    private static native long nCreateTextureLayer(long nativeProxy);
364    private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
365    private static native void nDestroyLayer(long nativeProxy, long layer);
366
367    private static native void nFence(long nativeProxy);
368}
369