ThreadedRenderer.java revision 18f16e6fba74eda173e1e7c869e6e2e2acc073ff
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.Trace;
23import android.view.Surface.OutOfResourcesException;
24import android.view.View.AttachInfo;
25
26import java.io.PrintWriter;
27
28/**
29 * Hardware renderer that proxies the rendering to a render thread. Most calls
30 * are currently synchronous.
31 * TODO: Make draw() async.
32 * TODO: Figure out how to share the DisplayList between two threads (global lock?)
33 *
34 * The UI thread can block on the RenderThread, but RenderThread must never
35 * block on the UI thread.
36 *
37 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates
38 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed
39 * by the lifecycle of the RenderProxy.
40 *
41 * Note that although currently the EGL context & surfaces are created & managed
42 * by the render thread, the goal is to move that into a shared structure that can
43 * be managed by both threads. EGLSurface creation & deletion should ideally be
44 * done on the UI thread and not the RenderThread to avoid stalling the
45 * RenderThread with surface buffer allocation.
46 *
47 * @hide
48 */
49public class ThreadedRenderer extends HardwareRenderer {
50    private static final String LOGTAG = "ThreadedRenderer";
51
52    private static final Rect NULL_RECT = new Rect();
53
54    private static final long NANOS_PER_MS = 1000000;
55
56    private int mWidth, mHeight;
57    private long mNativeProxy;
58    private boolean mInitialized = false;
59    private RenderNode mRootNode;
60    private Choreographer mChoreographer;
61
62    ThreadedRenderer(boolean translucent) {
63        long rootNodePtr = nCreateRootRenderNode();
64        mRootNode = RenderNode.adopt(rootNodePtr);
65        mRootNode.setClipToBounds(false);
66        mNativeProxy = nCreateProxy(translucent, rootNodePtr);
67
68        // Setup timing
69        mChoreographer = Choreographer.getInstance();
70        nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
71    }
72
73    @Override
74    void destroy(boolean full) {
75        mInitialized = false;
76        updateEnabledState(null);
77        nDestroyCanvasAndSurface(mNativeProxy);
78    }
79
80    private void updateEnabledState(Surface surface) {
81        if (surface == null || !surface.isValid()) {
82            setEnabled(false);
83        } else {
84            setEnabled(mInitialized);
85        }
86    }
87
88    @Override
89    boolean initialize(Surface surface) throws OutOfResourcesException {
90        mInitialized = true;
91        updateEnabledState(surface);
92        return nInitialize(mNativeProxy, surface);
93    }
94
95    @Override
96    void updateSurface(Surface surface) throws OutOfResourcesException {
97        updateEnabledState(surface);
98        nUpdateSurface(mNativeProxy, surface);
99    }
100
101    @Override
102    void pauseSurface(Surface surface) {
103        nPauseSurface(mNativeProxy, surface);
104    }
105
106    @Override
107    void destroyHardwareResources(View view) {
108        destroyResources(view);
109        // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
110    }
111
112    private static void destroyResources(View view) {
113        view.destroyHardwareResources();
114
115        if (view instanceof ViewGroup) {
116            ViewGroup group = (ViewGroup) view;
117
118            int count = group.getChildCount();
119            for (int i = 0; i < count; i++) {
120                destroyResources(group.getChildAt(i));
121            }
122        }
123    }
124
125    @Override
126    void invalidate(Surface surface) {
127        updateSurface(surface);
128    }
129
130    @Override
131    boolean safelyRun(Runnable action) {
132        nRunWithGlContext(mNativeProxy, action);
133        return true;
134    }
135
136    @Override
137    void setup(int width, int height) {
138        mWidth = width;
139        mHeight = height;
140        mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
141        nSetup(mNativeProxy, width, height);
142    }
143
144    @Override
145    int getWidth() {
146        return mWidth;
147    }
148
149    @Override
150    int getHeight() {
151        return mHeight;
152    }
153
154    @Override
155    void dumpGfxInfo(PrintWriter pw) {
156        // TODO Auto-generated method stub
157    }
158
159    @Override
160    long getFrameCount() {
161        // TODO Auto-generated method stub
162        return 0;
163    }
164
165    @Override
166    boolean loadSystemProperties() {
167        return false;
168    }
169
170    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
171        view.mPrivateFlags |= View.PFLAG_DRAWN;
172
173        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
174                == View.PFLAG_INVALIDATED;
175        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
176
177        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
178        HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
179        try {
180            callbacks.onHardwarePostDraw(canvas);
181            canvas.drawDisplayList(view.getDisplayList());
182            callbacks.onHardwarePostDraw(canvas);
183        } finally {
184            mRootNode.end(canvas);
185            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
186        }
187
188        view.mRecreateDisplayList = false;
189    }
190
191    @Override
192    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
193        attachInfo.mIgnoreDirtyState = true;
194        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
195        attachInfo.mDrawingTime = frameTimeNanos / NANOS_PER_MS;
196
197        updateRootDisplayList(view, callbacks);
198
199        attachInfo.mIgnoreDirtyState = false;
200
201        if (dirty == null) {
202            dirty = NULL_RECT;
203        }
204        nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
205                dirty.left, dirty.top, dirty.right, dirty.bottom);
206    }
207
208    @Override
209    void detachFunctor(long functor) {
210        // no-op, we never attach functors to need to detach them
211    }
212
213    @Override
214    void attachFunctor(AttachInfo attachInfo, long functor) {
215        invokeFunctor(functor, true);
216    }
217
218    @Override
219    void invokeFunctor(long functor, boolean waitForCompletion) {
220        nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
221    }
222
223    @Override
224    HardwareLayer createDisplayListLayer(int width, int height) {
225        long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
226        return HardwareLayer.adoptDisplayListLayer(this, layer);
227    }
228
229    @Override
230    HardwareLayer createTextureLayer() {
231        long layer = nCreateTextureLayer(mNativeProxy);
232        return HardwareLayer.adoptTextureLayer(this, layer);
233    }
234
235    @Override
236    SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
237        final SurfaceTexture[] ret = new SurfaceTexture[1];
238        nRunWithGlContext(mNativeProxy, new Runnable() {
239            @Override
240            public void run() {
241                ret[0] = layer.createSurfaceTexture();
242            }
243        });
244        return ret[0];
245    }
246
247    @Override
248    boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
249        return nCopyLayerInto(mNativeProxy,
250                layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
251    }
252
253    @Override
254    void pushLayerUpdate(HardwareLayer layer) {
255        // TODO: Remove this, it's not needed outside of GLRenderer
256    }
257
258    @Override
259    void onLayerCreated(HardwareLayer layer) {
260        // TODO: Is this actually useful?
261    }
262
263    @Override
264    void flushLayerUpdates() {
265        // TODO: Figure out what this should do or remove it
266    }
267
268    @Override
269    void onLayerDestroyed(HardwareLayer layer) {
270        nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
271    }
272
273    @Override
274    void setName(String name) {
275    }
276
277    @Override
278    void fence() {
279        nFence(mNativeProxy);
280    }
281
282    @Override
283    protected void finalize() throws Throwable {
284        try {
285            nDeleteProxy(mNativeProxy);
286            mNativeProxy = 0;
287        } finally {
288            super.finalize();
289        }
290    }
291
292    /** @hide */
293    public static native void postToRenderThread(Runnable runnable);
294
295    private static native long nCreateRootRenderNode();
296    private static native long nCreateProxy(boolean translucent, long rootRenderNode);
297    private static native void nDeleteProxy(long nativeProxy);
298
299    private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
300
301    private static native boolean nInitialize(long nativeProxy, Surface window);
302    private static native void nUpdateSurface(long nativeProxy, Surface window);
303    private static native void nPauseSurface(long nativeProxy, Surface window);
304    private static native void nSetup(long nativeProxy, int width, int height);
305    private static native void nSetDisplayListData(long nativeProxy, long displayList,
306            long newData);
307    private static native void nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
308            int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
309    private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
310    private static native void nDestroyCanvasAndSurface(long nativeProxy);
311
312    private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
313
314    private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
315    private static native long nCreateTextureLayer(long nativeProxy);
316    private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
317    private static native void nDestroyLayer(long nativeProxy, long layer);
318
319    private static native void nFence(long nativeProxy);
320}
321