blob: eaec8abe208b0bdc1a105f1116bcaf1c5a873516 [file] [log] [blame]
John Reckcec24ae2013-11-05 13:27:50 -08001/*
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
John Reck04fc5832014-02-05 16:38:25 -080019import android.graphics.Bitmap;
John Reckcec24ae2013-11-05 13:27:50 -080020import android.graphics.Rect;
21import android.graphics.SurfaceTexture;
John Reckcec24ae2013-11-05 13:27:50 -080022import android.os.SystemClock;
23import android.os.Trace;
John Reckcec24ae2013-11-05 13:27:50 -080024import android.view.Surface.OutOfResourcesException;
25import android.view.View.AttachInfo;
26
27import java.io.PrintWriter;
John Reckcec24ae2013-11-05 13:27:50 -080028
29/**
30 * Hardware renderer that proxies the rendering to a render thread. Most calls
John Reck4f02bf42014-01-03 18:09:17 -080031 * are currently synchronous.
32 * TODO: Make draw() async.
33 * TODO: Figure out how to share the DisplayList between two threads (global lock?)
John Reckcec24ae2013-11-05 13:27:50 -080034 *
35 * The UI thread can block on the RenderThread, but RenderThread must never
36 * block on the UI thread.
37 *
John Reck4f02bf42014-01-03 18:09:17 -080038 * 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 *
John Reckcec24ae2013-11-05 13:27:50 -080042 * 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
John Recke45b1fd2014-04-15 09:50:16 -070053 private static final Rect NULL_RECT = new Rect();
John Reckcec24ae2013-11-05 13:27:50 -080054
John Reckcec24ae2013-11-05 13:27:50 -080055 private int mWidth, mHeight;
John Reck4f02bf42014-01-03 18:09:17 -080056 private long mNativeProxy;
John Reckf7d9c1d2014-04-09 10:01:03 -070057 private boolean mInitialized = false;
John Reckbc0cc022014-04-11 16:08:14 -070058 private RenderNode mRootNode;
John Reckcec24ae2013-11-05 13:27:50 -080059
John Reck3dfe19f2013-12-13 14:25:19 -080060 ThreadedRenderer(boolean translucent) {
John Recke45b1fd2014-04-15 09:50:16 -070061 long rootNodePtr = nCreateRootRenderNode();
62 mRootNode = RenderNode.adopt(rootNodePtr);
John Reckbc0cc022014-04-11 16:08:14 -070063 mRootNode.setClipToBounds(false);
John Recke45b1fd2014-04-15 09:50:16 -070064 mNativeProxy = nCreateProxy(translucent, rootNodePtr);
John Reckcec24ae2013-11-05 13:27:50 -080065 }
66
67 @Override
68 void destroy(boolean full) {
John Reckf7d9c1d2014-04-09 10:01:03 -070069 mInitialized = false;
70 updateEnabledState(null);
John Reckfae904d2014-04-14 11:01:57 -070071 nDestroyCanvasAndSurface(mNativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -080072 }
73
John Reckf7d9c1d2014-04-09 10:01:03 -070074 private void updateEnabledState(Surface surface) {
75 if (surface == null || !surface.isValid()) {
76 setEnabled(false);
77 } else {
78 setEnabled(mInitialized);
79 }
80 }
81
John Reckcec24ae2013-11-05 13:27:50 -080082 @Override
83 boolean initialize(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -070084 mInitialized = true;
85 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -080086 return nInitialize(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -080087 }
88
89 @Override
90 void updateSurface(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -070091 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -080092 nUpdateSurface(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -080093 }
94
95 @Override
John Reckf7d9c1d2014-04-09 10:01:03 -070096 void pauseSurface(Surface surface) {
97 nPauseSurface(mNativeProxy, surface);
98 }
99
100 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800101 void destroyHardwareResources(View view) {
John Reck4f02bf42014-01-03 18:09:17 -0800102 destroyResources(view);
103 // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
104 }
105
106 private static void destroyResources(View view) {
107 view.destroyHardwareResources();
108
109 if (view instanceof ViewGroup) {
110 ViewGroup group = (ViewGroup) view;
111
112 int count = group.getChildCount();
113 for (int i = 0; i < count; i++) {
114 destroyResources(group.getChildAt(i));
115 }
116 }
John Reckcec24ae2013-11-05 13:27:50 -0800117 }
118
119 @Override
120 void invalidate(Surface surface) {
John Reck4f02bf42014-01-03 18:09:17 -0800121 updateSurface(surface);
John Reckcec24ae2013-11-05 13:27:50 -0800122 }
123
124 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800125 boolean safelyRun(Runnable action) {
John Reckfc53ef272014-02-11 10:40:25 -0800126 nRunWithGlContext(mNativeProxy, action);
127 return true;
John Reckcec24ae2013-11-05 13:27:50 -0800128 }
129
130 @Override
131 void setup(int width, int height) {
132 mWidth = width;
133 mHeight = height;
John Reckbc0cc022014-04-11 16:08:14 -0700134 mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
John Reck4f02bf42014-01-03 18:09:17 -0800135 nSetup(mNativeProxy, width, height);
John Reckcec24ae2013-11-05 13:27:50 -0800136 }
137
138 @Override
139 int getWidth() {
140 return mWidth;
141 }
142
143 @Override
144 int getHeight() {
145 return mHeight;
146 }
147
148 @Override
149 void dumpGfxInfo(PrintWriter pw) {
150 // TODO Auto-generated method stub
151 }
152
153 @Override
154 long getFrameCount() {
155 // TODO Auto-generated method stub
156 return 0;
157 }
158
159 @Override
160 boolean loadSystemProperties() {
John Reck4f02bf42014-01-03 18:09:17 -0800161 return false;
John Reckcec24ae2013-11-05 13:27:50 -0800162 }
163
John Reckcec24ae2013-11-05 13:27:50 -0800164 /**
165 * TODO: Remove
166 * Temporary hack to allow RenderThreadTest prototype app to trigger
167 * replaying a DisplayList after modifying the displaylist properties
168 *
169 * @hide */
170 public void repeatLastDraw() {
John Reckcec24ae2013-11-05 13:27:50 -0800171 }
172
John Reckbc0cc022014-04-11 16:08:14 -0700173 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
John Reckcec24ae2013-11-05 13:27:50 -0800174 view.mPrivateFlags |= View.PFLAG_DRAWN;
175
176 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
177 == View.PFLAG_INVALIDATED;
178 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
179
180 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
John Reckbc0cc022014-04-11 16:08:14 -0700181 HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
John Reck05e85842014-04-23 14:48:28 -0700182 try {
183 callbacks.onHardwarePostDraw(canvas);
184 canvas.drawDisplayList(view.getDisplayList());
185 callbacks.onHardwarePostDraw(canvas);
186 } finally {
187 mRootNode.end(canvas);
188 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
189 }
John Reckcec24ae2013-11-05 13:27:50 -0800190
191 view.mRecreateDisplayList = false;
John Reckbc0cc022014-04-11 16:08:14 -0700192 }
193
194 @Override
195 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
196 attachInfo.mIgnoreDirtyState = true;
197 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
198
199 updateRootDisplayList(view, callbacks);
John Reckcec24ae2013-11-05 13:27:50 -0800200
John Reck6313b922014-04-16 18:59:21 -0700201 attachInfo.mIgnoreDirtyState = false;
202
John Reck4f02bf42014-01-03 18:09:17 -0800203 if (dirty == null) {
204 dirty = NULL_RECT;
205 }
John Recke45b1fd2014-04-15 09:50:16 -0700206 nSyncAndDrawFrame(mNativeProxy, dirty.left, dirty.top, dirty.right, dirty.bottom);
John Reckcec24ae2013-11-05 13:27:50 -0800207 }
208
209 @Override
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000210 void detachFunctor(long functor) {
John Reckd3d8daf2014-04-10 15:00:13 -0700211 // no-op, we never attach functors to need to detach them
John Reckcec24ae2013-11-05 13:27:50 -0800212 }
213
214 @Override
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000215 void attachFunctor(AttachInfo attachInfo, long functor) {
John Reckd3d8daf2014-04-10 15:00:13 -0700216 invokeFunctor(functor, true);
John Reckcec24ae2013-11-05 13:27:50 -0800217 }
218
219 @Override
Bo Liuae738a72014-04-27 16:22:04 -0700220 void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck0d1f6342014-03-28 20:30:27 -0700221 nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
222 }
223
224 @Override
John Reck19b6bcf2014-02-14 20:03:38 -0800225 HardwareLayer createDisplayListLayer(int width, int height) {
226 long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
227 return HardwareLayer.adoptDisplayListLayer(this, layer);
228 }
229
230 @Override
231 HardwareLayer createTextureLayer() {
232 long layer = nCreateTextureLayer(mNativeProxy);
233 return HardwareLayer.adoptTextureLayer(this, layer);
234 }
235
236 @Override
237 SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
238 final SurfaceTexture[] ret = new SurfaceTexture[1];
239 nRunWithGlContext(mNativeProxy, new Runnable() {
240 @Override
241 public void run() {
242 ret[0] = layer.createSurfaceTexture();
243 }
244 });
245 return ret[0];
246 }
247
248 @Override
249 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
250 return nCopyLayerInto(mNativeProxy,
251 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
252 }
253
254 @Override
255 void pushLayerUpdate(HardwareLayer layer) {
256 // TODO: Remove this, it's not needed outside of GLRenderer
257 }
258
259 @Override
260 void onLayerCreated(HardwareLayer layer) {
261 // TODO: Is this actually useful?
262 }
263
264 @Override
265 void flushLayerUpdates() {
266 // TODO: Figure out what this should do or remove it
267 }
268
269 @Override
270 void onLayerDestroyed(HardwareLayer layer) {
271 nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
272 }
273
274 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800275 void setName(String name) {
John Reckcec24ae2013-11-05 13:27:50 -0800276 }
277
John Reck4f02bf42014-01-03 18:09:17 -0800278 @Override
John Reck28ad7b52014-04-07 16:59:25 -0700279 void fence() {
280 nFence(mNativeProxy);
281 }
282
283 @Override
John Reck4f02bf42014-01-03 18:09:17 -0800284 protected void finalize() throws Throwable {
285 try {
286 nDeleteProxy(mNativeProxy);
John Reck0ed751d2014-04-08 14:10:17 -0700287 mNativeProxy = 0;
John Reck4f02bf42014-01-03 18:09:17 -0800288 } finally {
289 super.finalize();
John Reckcec24ae2013-11-05 13:27:50 -0800290 }
291 }
292
293 /** @hide */
294 public static native void postToRenderThread(Runnable runnable);
John Reck4f02bf42014-01-03 18:09:17 -0800295
John Recke45b1fd2014-04-15 09:50:16 -0700296 private static native long nCreateRootRenderNode();
297 private static native long nCreateProxy(boolean translucent, long rootRenderNode);
John Reck4f02bf42014-01-03 18:09:17 -0800298 private static native void nDeleteProxy(long nativeProxy);
299
300 private static native boolean nInitialize(long nativeProxy, Surface window);
301 private static native void nUpdateSurface(long nativeProxy, Surface window);
John Reckf7d9c1d2014-04-09 10:01:03 -0700302 private static native void nPauseSurface(long nativeProxy, Surface window);
John Reck4f02bf42014-01-03 18:09:17 -0800303 private static native void nSetup(long nativeProxy, int width, int height);
John Reckbe34f2f2014-03-10 08:58:44 -0700304 private static native void nSetDisplayListData(long nativeProxy, long displayList,
John Reck44fd8d22014-02-26 11:00:11 -0800305 long newData);
John Recke45b1fd2014-04-15 09:50:16 -0700306 private static native void nSyncAndDrawFrame(long nativeProxy,
John Reck4f02bf42014-01-03 18:09:17 -0800307 int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
John Reckfc53ef272014-02-11 10:40:25 -0800308 private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
John Reckfae904d2014-04-14 11:01:57 -0700309 private static native void nDestroyCanvasAndSurface(long nativeProxy);
John Reck4f02bf42014-01-03 18:09:17 -0800310
John Reck0d1f6342014-03-28 20:30:27 -0700311 private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
John Reck19b6bcf2014-02-14 20:03:38 -0800312
313 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
314 private static native long nCreateTextureLayer(long nativeProxy);
315 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
316 private static native void nDestroyLayer(long nativeProxy, long layer);
John Reck28ad7b52014-04-07 16:59:25 -0700317
318 private static native void nFence(long nativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -0800319}