ThreadedRenderer.java revision d72e0a339b54af0c4e731513bbad120dff694723
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.SystemProperties;
26import android.os.Trace;
27import android.util.Log;
28import android.util.TimeUtils;
29import android.view.Surface.OutOfResourcesException;
30import android.view.View.AttachInfo;
31
32import java.io.FileDescriptor;
33import java.io.PrintWriter;
34
35/**
36 * Hardware renderer that proxies the rendering to a render thread. Most calls
37 * are currently synchronous.
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 static final String[] VISUALIZERS = {
66        PROFILE_PROPERTY_VISUALIZE_BARS,
67    };
68
69    private int mWidth, mHeight;
70    private long mNativeProxy;
71    private boolean mInitialized = false;
72    private RenderNode mRootNode;
73    private Choreographer mChoreographer;
74    private boolean mProfilingEnabled;
75
76    ThreadedRenderer(boolean translucent) {
77        AtlasInitializer.sInstance.init();
78
79        long rootNodePtr = nCreateRootRenderNode();
80        mRootNode = RenderNode.adopt(rootNodePtr);
81        mRootNode.setClipToBounds(false);
82        mNativeProxy = nCreateProxy(translucent, rootNodePtr);
83
84        // Setup timing
85        mChoreographer = Choreographer.getInstance();
86        nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
87
88        loadSystemProperties();
89    }
90
91    @Override
92    void destroy(boolean full) {
93        mInitialized = false;
94        updateEnabledState(null);
95        nDestroyCanvasAndSurface(mNativeProxy);
96    }
97
98    private void updateEnabledState(Surface surface) {
99        if (surface == null || !surface.isValid()) {
100            setEnabled(false);
101        } else {
102            setEnabled(mInitialized);
103        }
104    }
105
106    @Override
107    boolean initialize(Surface surface) throws OutOfResourcesException {
108        mInitialized = true;
109        updateEnabledState(surface);
110        return nInitialize(mNativeProxy, surface);
111    }
112
113    @Override
114    void updateSurface(Surface surface) throws OutOfResourcesException {
115        updateEnabledState(surface);
116        nUpdateSurface(mNativeProxy, surface);
117    }
118
119    @Override
120    void pauseSurface(Surface surface) {
121        nPauseSurface(mNativeProxy, surface);
122    }
123
124    @Override
125    void destroyHardwareResources(View view) {
126        destroyResources(view);
127        nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS);
128    }
129
130    private static void destroyResources(View view) {
131        view.destroyHardwareResources();
132
133        if (view instanceof ViewGroup) {
134            ViewGroup group = (ViewGroup) view;
135
136            int count = group.getChildCount();
137            for (int i = 0; i < count; i++) {
138                destroyResources(group.getChildAt(i));
139            }
140        }
141    }
142
143    @Override
144    void invalidate(Surface surface) {
145        updateSurface(surface);
146    }
147
148    @Override
149    boolean safelyRun(Runnable action) {
150        nRunWithGlContext(mNativeProxy, action);
151        return true;
152    }
153
154    @Override
155    void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) {
156        mWidth = width;
157        mHeight = height;
158        mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
159        nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius);
160    }
161
162    @Override
163    void setOpaque(boolean opaque) {
164        nSetOpaque(mNativeProxy, opaque);
165    }
166
167    @Override
168    int getWidth() {
169        return mWidth;
170    }
171
172    @Override
173    int getHeight() {
174        return mHeight;
175    }
176
177    @Override
178    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
179        pw.flush();
180        nDumpProfileInfo(mNativeProxy, fd);
181    }
182
183    private static int search(String[] values, String value) {
184        for (int i = 0; i < values.length; i++) {
185            if (values[i].equals(value)) return i;
186        }
187        return -1;
188    }
189
190    private static boolean checkIfProfilingRequested() {
191        String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY);
192        int graphType = search(VISUALIZERS, profiling);
193        return (graphType >= 0) || Boolean.parseBoolean(profiling);
194    }
195
196    @Override
197    boolean loadSystemProperties() {
198        boolean changed = nLoadSystemProperties(mNativeProxy);
199        boolean wantProfiling = checkIfProfilingRequested();
200        if (wantProfiling != mProfilingEnabled) {
201            mProfilingEnabled = wantProfiling;
202            changed = true;
203        }
204        return changed;
205    }
206
207    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
208        view.mPrivateFlags |= View.PFLAG_DRAWN;
209
210        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
211                == View.PFLAG_INVALIDATED;
212        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
213
214        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
215        HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
216        try {
217            canvas.save();
218            callbacks.onHardwarePreDraw(canvas);
219            canvas.drawDisplayList(view.getDisplayList());
220            callbacks.onHardwarePostDraw(canvas);
221            canvas.restore();
222        } finally {
223            mRootNode.end(canvas);
224            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
225        }
226
227        view.mRecreateDisplayList = false;
228    }
229
230    @Override
231    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
232        attachInfo.mIgnoreDirtyState = true;
233        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
234        attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
235
236        long recordDuration = 0;
237        if (mProfilingEnabled) {
238            recordDuration = System.nanoTime();
239        }
240
241        updateRootDisplayList(view, callbacks);
242
243        if (mProfilingEnabled) {
244            recordDuration = System.nanoTime() - recordDuration;
245        }
246
247        attachInfo.mIgnoreDirtyState = false;
248
249        if (dirty == null) {
250            dirty = NULL_RECT;
251        }
252        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
253                recordDuration, view.getResources().getDisplayMetrics().density,
254                dirty.left, dirty.top, dirty.right, dirty.bottom);
255        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
256            attachInfo.mViewRootImpl.invalidate();
257        }
258    }
259
260    @Override
261    void invokeFunctor(long functor, boolean waitForCompletion) {
262        nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
263    }
264
265    @Override
266    HardwareLayer createDisplayListLayer(int width, int height) {
267        long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
268        return HardwareLayer.adoptDisplayListLayer(this, layer);
269    }
270
271    @Override
272    HardwareLayer createTextureLayer() {
273        long layer = nCreateTextureLayer(mNativeProxy);
274        return HardwareLayer.adoptTextureLayer(this, layer);
275    }
276
277    @Override
278    SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
279        final SurfaceTexture[] ret = new SurfaceTexture[1];
280        nRunWithGlContext(mNativeProxy, new Runnable() {
281            @Override
282            public void run() {
283                ret[0] = layer.createSurfaceTexture();
284            }
285        });
286        return ret[0];
287    }
288
289    @Override
290    boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
291        return nCopyLayerInto(mNativeProxy,
292                layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
293    }
294
295    @Override
296    void pushLayerUpdate(HardwareLayer layer) {
297        nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
298    }
299
300    @Override
301    void flushLayerUpdates() {
302        // TODO: Figure out what this should do or remove it
303    }
304
305    @Override
306    void onLayerDestroyed(HardwareLayer layer) {
307        nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
308    }
309
310    @Override
311    void setName(String name) {
312    }
313
314    @Override
315    void fence() {
316        nFence(mNativeProxy);
317    }
318
319    @Override
320    public void notifyFramePending() {
321        nNotifyFramePending(mNativeProxy);
322    }
323
324    @Override
325    protected void finalize() throws Throwable {
326        try {
327            nDeleteProxy(mNativeProxy);
328            mNativeProxy = 0;
329        } finally {
330            super.finalize();
331        }
332    }
333
334    private static class AtlasInitializer {
335        static AtlasInitializer sInstance = new AtlasInitializer();
336
337        private boolean mInitialized = false;
338
339        private AtlasInitializer() {}
340
341        synchronized void init() {
342            if (mInitialized) return;
343            IBinder binder = ServiceManager.getService("assetatlas");
344            if (binder == null) return;
345
346            IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
347            try {
348                if (atlas.isCompatible(android.os.Process.myPpid())) {
349                    GraphicBuffer buffer = atlas.getBuffer();
350                    if (buffer != null) {
351                        long[] map = atlas.getMap();
352                        if (map != null) {
353                            nSetAtlas(buffer, map);
354                            mInitialized = true;
355                        }
356                        // If IAssetAtlas is not the same class as the IBinder
357                        // we are using a remote service and we can safely
358                        // destroy the graphic buffer
359                        if (atlas.getClass() != binder.getClass()) {
360                            buffer.destroy();
361                        }
362                    }
363                }
364            } catch (RemoteException e) {
365                Log.w(LOG_TAG, "Could not acquire atlas", e);
366            }
367        }
368    }
369
370    private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
371
372    private static native long nCreateRootRenderNode();
373    private static native long nCreateProxy(boolean translucent, long rootRenderNode);
374    private static native void nDeleteProxy(long nativeProxy);
375
376    private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
377    private static native boolean nLoadSystemProperties(long nativeProxy);
378
379    private static native boolean nInitialize(long nativeProxy, Surface window);
380    private static native void nUpdateSurface(long nativeProxy, Surface window);
381    private static native void nPauseSurface(long nativeProxy, Surface window);
382    private static native void nSetup(long nativeProxy, int width, int height,
383            float lightX, float lightY, float lightZ, float lightRadius);
384    private static native void nSetOpaque(long nativeProxy, boolean opaque);
385    private static native int nSyncAndDrawFrame(long nativeProxy,
386            long frameTimeNanos, long recordDuration, float density,
387            int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
388    private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
389    private static native void nDestroyCanvasAndSurface(long nativeProxy);
390
391    private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
392
393    private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
394    private static native long nCreateTextureLayer(long nativeProxy);
395    private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
396    private static native void nPushLayerUpdate(long nativeProxy, long layer);
397    private static native void nCancelLayerUpdate(long nativeProxy, long layer);
398
399    private static native void nFlushCaches(long nativeProxy, int flushMode);
400
401    private static native void nFence(long nativeProxy);
402    private static native void nNotifyFramePending(long nativeProxy);
403
404    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
405}
406