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