ThreadedRenderer.java revision ef27453cf71e331e4076df5e5c665b06d5c3e050
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    // Keep in sync with DrawFrameTask.h SYNC_* flags
57    // Nothing interesting to report
58    private static final int SYNC_OK = 0x0;
59    // Needs a ViewRoot invalidate
60    private static final int SYNC_INVALIDATE_REQUIRED = 0x1;
61
62    private int mWidth, mHeight;
63    private long mNativeProxy;
64    private boolean mInitialized = false;
65    private RenderNode mRootNode;
66    private Choreographer mChoreographer;
67
68    ThreadedRenderer(boolean translucent) {
69        long rootNodePtr = nCreateRootRenderNode();
70        mRootNode = RenderNode.adopt(rootNodePtr);
71        mRootNode.setClipToBounds(false);
72        mNativeProxy = nCreateProxy(translucent, rootNodePtr);
73
74        // Setup timing
75        mChoreographer = Choreographer.getInstance();
76        nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
77    }
78
79    @Override
80    void destroy(boolean full) {
81        mInitialized = false;
82        updateEnabledState(null);
83        nDestroyCanvasAndSurface(mNativeProxy);
84    }
85
86    private void updateEnabledState(Surface surface) {
87        if (surface == null || !surface.isValid()) {
88            setEnabled(false);
89        } else {
90            setEnabled(mInitialized);
91        }
92    }
93
94    @Override
95    boolean initialize(Surface surface) throws OutOfResourcesException {
96        mInitialized = true;
97        updateEnabledState(surface);
98        return nInitialize(mNativeProxy, surface);
99    }
100
101    @Override
102    void updateSurface(Surface surface) throws OutOfResourcesException {
103        updateEnabledState(surface);
104        nUpdateSurface(mNativeProxy, surface);
105    }
106
107    @Override
108    void pauseSurface(Surface surface) {
109        nPauseSurface(mNativeProxy, surface);
110    }
111
112    @Override
113    void destroyHardwareResources(View view) {
114        destroyResources(view);
115        // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
116    }
117
118    private static void destroyResources(View view) {
119        view.destroyHardwareResources();
120
121        if (view instanceof ViewGroup) {
122            ViewGroup group = (ViewGroup) view;
123
124            int count = group.getChildCount();
125            for (int i = 0; i < count; i++) {
126                destroyResources(group.getChildAt(i));
127            }
128        }
129    }
130
131    @Override
132    void invalidate(Surface surface) {
133        updateSurface(surface);
134    }
135
136    @Override
137    boolean safelyRun(Runnable action) {
138        nRunWithGlContext(mNativeProxy, action);
139        return true;
140    }
141
142    @Override
143    void setup(int width, int height) {
144        mWidth = width;
145        mHeight = height;
146        mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
147        nSetup(mNativeProxy, width, height);
148    }
149
150    @Override
151    void setOpaque(boolean opaque) {
152        nSetOpaque(mNativeProxy, opaque);
153    }
154
155    @Override
156    int getWidth() {
157        return mWidth;
158    }
159
160    @Override
161    int getHeight() {
162        return mHeight;
163    }
164
165    @Override
166    void dumpGfxInfo(PrintWriter pw) {
167        // TODO Auto-generated method stub
168    }
169
170    @Override
171    long getFrameCount() {
172        // TODO Auto-generated method stub
173        return 0;
174    }
175
176    @Override
177    boolean loadSystemProperties() {
178        return nLoadSystemProperties(mNativeProxy);
179    }
180
181    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
182        view.mPrivateFlags |= View.PFLAG_DRAWN;
183
184        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
185                == View.PFLAG_INVALIDATED;
186        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
187
188        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
189        HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
190        try {
191            callbacks.onHardwarePostDraw(canvas);
192            canvas.drawDisplayList(view.getDisplayList());
193            callbacks.onHardwarePostDraw(canvas);
194        } finally {
195            mRootNode.end(canvas);
196            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
197        }
198
199        view.mRecreateDisplayList = false;
200    }
201
202    @Override
203    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
204        attachInfo.mIgnoreDirtyState = true;
205        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
206        attachInfo.mDrawingTime = frameTimeNanos / NANOS_PER_MS;
207
208        updateRootDisplayList(view, callbacks);
209
210        attachInfo.mIgnoreDirtyState = false;
211
212        if (dirty == null) {
213            dirty = NULL_RECT;
214        }
215        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
216                dirty.left, dirty.top, dirty.right, dirty.bottom);
217        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
218            attachInfo.mViewRootImpl.invalidate();
219        }
220    }
221
222    @Override
223    void invokeFunctor(long functor, boolean waitForCompletion) {
224        nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
225    }
226
227    @Override
228    HardwareLayer createDisplayListLayer(int width, int height) {
229        long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
230        return HardwareLayer.adoptDisplayListLayer(this, layer);
231    }
232
233    @Override
234    HardwareLayer createTextureLayer() {
235        long layer = nCreateTextureLayer(mNativeProxy);
236        return HardwareLayer.adoptTextureLayer(this, layer);
237    }
238
239    @Override
240    SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
241        final SurfaceTexture[] ret = new SurfaceTexture[1];
242        nRunWithGlContext(mNativeProxy, new Runnable() {
243            @Override
244            public void run() {
245                ret[0] = layer.createSurfaceTexture();
246            }
247        });
248        return ret[0];
249    }
250
251    @Override
252    boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
253        return nCopyLayerInto(mNativeProxy,
254                layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
255    }
256
257    @Override
258    void pushLayerUpdate(HardwareLayer layer) {
259        // TODO: Remove this, it's not needed outside of GLRenderer
260    }
261
262    @Override
263    void onLayerCreated(HardwareLayer layer) {
264        // TODO: Is this actually useful?
265    }
266
267    @Override
268    void flushLayerUpdates() {
269        // TODO: Figure out what this should do or remove it
270    }
271
272    @Override
273    void onLayerDestroyed(HardwareLayer layer) {
274        nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
275    }
276
277    @Override
278    void setName(String name) {
279    }
280
281    @Override
282    void fence() {
283        nFence(mNativeProxy);
284    }
285
286    @Override
287    protected void finalize() throws Throwable {
288        try {
289            nDeleteProxy(mNativeProxy);
290            mNativeProxy = 0;
291        } finally {
292            super.finalize();
293        }
294    }
295
296    /** @hide */
297    public static native void postToRenderThread(Runnable runnable);
298
299    private static native long nCreateRootRenderNode();
300    private static native long nCreateProxy(boolean translucent, long rootRenderNode);
301    private static native void nDeleteProxy(long nativeProxy);
302
303    private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
304    private static native boolean nLoadSystemProperties(long nativeProxy);
305
306    private static native boolean nInitialize(long nativeProxy, Surface window);
307    private static native void nUpdateSurface(long nativeProxy, Surface window);
308    private static native void nPauseSurface(long nativeProxy, Surface window);
309    private static native void nSetup(long nativeProxy, int width, int height);
310    private static native void nSetOpaque(long nativeProxy, boolean opaque);
311    private static native void nSetDisplayListData(long nativeProxy, long displayList,
312            long newData);
313    private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
314            int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
315    private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
316    private static native void nDestroyCanvasAndSurface(long nativeProxy);
317
318    private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
319
320    private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
321    private static native long nCreateTextureLayer(long nativeProxy);
322    private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
323    private static native void nDestroyLayer(long nativeProxy, long layer);
324
325    private static native void nFence(long nativeProxy);
326}
327