blob: 704d516874ee920266e428c41a7827d0f7345507 [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 Reck66f0be62014-05-13 13:39:31 -070022import android.os.IBinder;
23import android.os.RemoteException;
24import android.os.ServiceManager;
John Reckcec24ae2013-11-05 13:27:50 -080025import android.os.Trace;
John Reck66f0be62014-05-13 13:39:31 -070026import android.util.Log;
John Reck315c3292014-05-09 19:21:04 -070027import android.util.TimeUtils;
John Reckcec24ae2013-11-05 13:27:50 -080028import android.view.Surface.OutOfResourcesException;
29import android.view.View.AttachInfo;
30
31import java.io.PrintWriter;
John Reckcec24ae2013-11-05 13:27:50 -080032
33/**
34 * Hardware renderer that proxies the rendering to a render thread. Most calls
John Reck4f02bf42014-01-03 18:09:17 -080035 * are currently synchronous.
36 * TODO: Make draw() async.
37 * TODO: Figure out how to share the DisplayList between two threads (global lock?)
John Reckcec24ae2013-11-05 13:27:50 -080038 *
39 * The UI thread can block on the RenderThread, but RenderThread must never
40 * block on the UI thread.
41 *
John Reck4f02bf42014-01-03 18:09:17 -080042 * 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 *
John Reckcec24ae2013-11-05 13:27:50 -080046 * 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
John Recke45b1fd2014-04-15 09:50:16 -070057 private static final Rect NULL_RECT = new Rect();
John Reckcec24ae2013-11-05 13:27:50 -080058
John Reckf9be7792014-05-02 18:21:16 -070059 // 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
John Reckcec24ae2013-11-05 13:27:50 -080065 private int mWidth, mHeight;
John Reck4f02bf42014-01-03 18:09:17 -080066 private long mNativeProxy;
John Reckf7d9c1d2014-04-09 10:01:03 -070067 private boolean mInitialized = false;
John Reckbc0cc022014-04-11 16:08:14 -070068 private RenderNode mRootNode;
John Reck18f16e62014-05-02 16:46:41 -070069 private Choreographer mChoreographer;
John Reckcec24ae2013-11-05 13:27:50 -080070
John Reck3dfe19f2013-12-13 14:25:19 -080071 ThreadedRenderer(boolean translucent) {
John Reck66f0be62014-05-13 13:39:31 -070072 AtlasInitializer.sInstance.init();
73
John Recke45b1fd2014-04-15 09:50:16 -070074 long rootNodePtr = nCreateRootRenderNode();
75 mRootNode = RenderNode.adopt(rootNodePtr);
John Reckbc0cc022014-04-11 16:08:14 -070076 mRootNode.setClipToBounds(false);
John Recke45b1fd2014-04-15 09:50:16 -070077 mNativeProxy = nCreateProxy(translucent, rootNodePtr);
John Reck18f16e62014-05-02 16:46:41 -070078
79 // Setup timing
80 mChoreographer = Choreographer.getInstance();
81 nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
John Reckcec24ae2013-11-05 13:27:50 -080082 }
83
84 @Override
85 void destroy(boolean full) {
John Reckf7d9c1d2014-04-09 10:01:03 -070086 mInitialized = false;
87 updateEnabledState(null);
John Reckfae904d2014-04-14 11:01:57 -070088 nDestroyCanvasAndSurface(mNativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -080089 }
90
John Reckf7d9c1d2014-04-09 10:01:03 -070091 private void updateEnabledState(Surface surface) {
92 if (surface == null || !surface.isValid()) {
93 setEnabled(false);
94 } else {
95 setEnabled(mInitialized);
96 }
97 }
98
John Reckcec24ae2013-11-05 13:27:50 -080099 @Override
100 boolean initialize(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700101 mInitialized = true;
102 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -0800103 return nInitialize(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800104 }
105
106 @Override
107 void updateSurface(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700108 updateEnabledState(surface);
John Reck4f02bf42014-01-03 18:09:17 -0800109 nUpdateSurface(mNativeProxy, surface);
John Reckcec24ae2013-11-05 13:27:50 -0800110 }
111
112 @Override
John Reckf7d9c1d2014-04-09 10:01:03 -0700113 void pauseSurface(Surface surface) {
114 nPauseSurface(mNativeProxy, surface);
115 }
116
117 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800118 void destroyHardwareResources(View view) {
John Reck4f02bf42014-01-03 18:09:17 -0800119 destroyResources(view);
120 // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
121 }
122
123 private static void destroyResources(View view) {
124 view.destroyHardwareResources();
125
126 if (view instanceof ViewGroup) {
127 ViewGroup group = (ViewGroup) view;
128
129 int count = group.getChildCount();
130 for (int i = 0; i < count; i++) {
131 destroyResources(group.getChildAt(i));
132 }
133 }
John Reckcec24ae2013-11-05 13:27:50 -0800134 }
135
136 @Override
137 void invalidate(Surface surface) {
John Reck4f02bf42014-01-03 18:09:17 -0800138 updateSurface(surface);
John Reckcec24ae2013-11-05 13:27:50 -0800139 }
140
141 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800142 boolean safelyRun(Runnable action) {
John Reckfc53ef272014-02-11 10:40:25 -0800143 nRunWithGlContext(mNativeProxy, action);
144 return true;
John Reckcec24ae2013-11-05 13:27:50 -0800145 }
146
147 @Override
Chris Craik797b95b2014-05-20 18:10:25 -0700148 void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) {
John Reckcec24ae2013-11-05 13:27:50 -0800149 mWidth = width;
150 mHeight = height;
John Reckbc0cc022014-04-11 16:08:14 -0700151 mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
Chris Craik797b95b2014-05-20 18:10:25 -0700152 nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius);
John Reckcec24ae2013-11-05 13:27:50 -0800153 }
154
155 @Override
John Reck63a06672014-05-07 13:45:54 -0700156 void setOpaque(boolean opaque) {
157 nSetOpaque(mNativeProxy, opaque);
158 }
159
160 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800161 int getWidth() {
162 return mWidth;
163 }
164
165 @Override
166 int getHeight() {
167 return mHeight;
168 }
169
170 @Override
171 void dumpGfxInfo(PrintWriter pw) {
172 // TODO Auto-generated method stub
173 }
174
175 @Override
176 long getFrameCount() {
177 // TODO Auto-generated method stub
178 return 0;
179 }
180
181 @Override
182 boolean loadSystemProperties() {
John Recke4280ba2014-05-05 16:39:37 -0700183 return nLoadSystemProperties(mNativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -0800184 }
185
John Reckbc0cc022014-04-11 16:08:14 -0700186 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
John Reckcec24ae2013-11-05 13:27:50 -0800187 view.mPrivateFlags |= View.PFLAG_DRAWN;
188
189 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
190 == View.PFLAG_INVALIDATED;
191 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
192
193 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
John Reckbc0cc022014-04-11 16:08:14 -0700194 HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
John Reck05e85842014-04-23 14:48:28 -0700195 try {
John Reck86faf9e2014-05-19 13:19:07 -0700196 canvas.save();
Alan Viveretted5b2ec42014-05-17 16:34:09 -0700197 callbacks.onHardwarePreDraw(canvas);
John Reck05e85842014-04-23 14:48:28 -0700198 canvas.drawDisplayList(view.getDisplayList());
199 callbacks.onHardwarePostDraw(canvas);
John Reck86faf9e2014-05-19 13:19:07 -0700200 canvas.restore();
John Reck05e85842014-04-23 14:48:28 -0700201 } finally {
202 mRootNode.end(canvas);
203 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
204 }
John Reckcec24ae2013-11-05 13:27:50 -0800205
206 view.mRecreateDisplayList = false;
John Reckbc0cc022014-04-11 16:08:14 -0700207 }
208
209 @Override
210 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
211 attachInfo.mIgnoreDirtyState = true;
John Reck18f16e62014-05-02 16:46:41 -0700212 long frameTimeNanos = mChoreographer.getFrameTimeNanos();
John Reck315c3292014-05-09 19:21:04 -0700213 attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
John Reckbc0cc022014-04-11 16:08:14 -0700214
215 updateRootDisplayList(view, callbacks);
John Reckcec24ae2013-11-05 13:27:50 -0800216
John Reck6313b922014-04-16 18:59:21 -0700217 attachInfo.mIgnoreDirtyState = false;
218
John Reck4f02bf42014-01-03 18:09:17 -0800219 if (dirty == null) {
220 dirty = NULL_RECT;
221 }
John Reckf9be7792014-05-02 18:21:16 -0700222 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
John Reck18f16e62014-05-02 16:46:41 -0700223 dirty.left, dirty.top, dirty.right, dirty.bottom);
John Reckf9be7792014-05-02 18:21:16 -0700224 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
225 attachInfo.mViewRootImpl.invalidate();
226 }
John Reckcec24ae2013-11-05 13:27:50 -0800227 }
228
229 @Override
Bo Liuae738a72014-04-27 16:22:04 -0700230 void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck0d1f6342014-03-28 20:30:27 -0700231 nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
232 }
233
234 @Override
John Reck19b6bcf2014-02-14 20:03:38 -0800235 HardwareLayer createDisplayListLayer(int width, int height) {
236 long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
237 return HardwareLayer.adoptDisplayListLayer(this, layer);
238 }
239
240 @Override
241 HardwareLayer createTextureLayer() {
242 long layer = nCreateTextureLayer(mNativeProxy);
243 return HardwareLayer.adoptTextureLayer(this, layer);
244 }
245
246 @Override
247 SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
248 final SurfaceTexture[] ret = new SurfaceTexture[1];
249 nRunWithGlContext(mNativeProxy, new Runnable() {
250 @Override
251 public void run() {
252 ret[0] = layer.createSurfaceTexture();
253 }
254 });
255 return ret[0];
256 }
257
258 @Override
259 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
260 return nCopyLayerInto(mNativeProxy,
261 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
262 }
263
264 @Override
265 void pushLayerUpdate(HardwareLayer layer) {
266 // TODO: Remove this, it's not needed outside of GLRenderer
267 }
268
269 @Override
270 void onLayerCreated(HardwareLayer layer) {
271 // TODO: Is this actually useful?
272 }
273
274 @Override
275 void flushLayerUpdates() {
276 // TODO: Figure out what this should do or remove it
277 }
278
279 @Override
280 void onLayerDestroyed(HardwareLayer layer) {
281 nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
282 }
283
284 @Override
John Reckcec24ae2013-11-05 13:27:50 -0800285 void setName(String name) {
John Reckcec24ae2013-11-05 13:27:50 -0800286 }
287
John Reck4f02bf42014-01-03 18:09:17 -0800288 @Override
John Reck28ad7b52014-04-07 16:59:25 -0700289 void fence() {
290 nFence(mNativeProxy);
291 }
292
293 @Override
John Reck4f02bf42014-01-03 18:09:17 -0800294 protected void finalize() throws Throwable {
295 try {
296 nDeleteProxy(mNativeProxy);
John Reck0ed751d2014-04-08 14:10:17 -0700297 mNativeProxy = 0;
John Reck4f02bf42014-01-03 18:09:17 -0800298 } finally {
299 super.finalize();
John Reckcec24ae2013-11-05 13:27:50 -0800300 }
301 }
302
John Reck66f0be62014-05-13 13:39:31 -0700303 private static class AtlasInitializer {
304 static AtlasInitializer sInstance = new AtlasInitializer();
305
306 private boolean mInitialized = false;
307
308 private AtlasInitializer() {}
309
310 synchronized void init() {
311 if (mInitialized) return;
312 IBinder binder = ServiceManager.getService("assetatlas");
313 if (binder == null) return;
314
315 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
316 try {
317 if (atlas.isCompatible(android.os.Process.myPpid())) {
318 GraphicBuffer buffer = atlas.getBuffer();
319 if (buffer != null) {
320 long[] map = atlas.getMap();
321 if (map != null) {
322 nSetAtlas(buffer, map);
323 mInitialized = true;
324 }
325 // If IAssetAtlas is not the same class as the IBinder
326 // we are using a remote service and we can safely
327 // destroy the graphic buffer
328 if (atlas.getClass() != binder.getClass()) {
329 buffer.destroy();
330 }
331 }
332 }
333 } catch (RemoteException e) {
334 Log.w(LOG_TAG, "Could not acquire atlas", e);
335 }
336 }
337 }
338
339 private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
John Reck4f02bf42014-01-03 18:09:17 -0800340
John Recke45b1fd2014-04-15 09:50:16 -0700341 private static native long nCreateRootRenderNode();
342 private static native long nCreateProxy(boolean translucent, long rootRenderNode);
John Reck4f02bf42014-01-03 18:09:17 -0800343 private static native void nDeleteProxy(long nativeProxy);
344
John Reck18f16e62014-05-02 16:46:41 -0700345 private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
John Recke4280ba2014-05-05 16:39:37 -0700346 private static native boolean nLoadSystemProperties(long nativeProxy);
John Reck18f16e62014-05-02 16:46:41 -0700347
John Reck4f02bf42014-01-03 18:09:17 -0800348 private static native boolean nInitialize(long nativeProxy, Surface window);
349 private static native void nUpdateSurface(long nativeProxy, Surface window);
John Reckf7d9c1d2014-04-09 10:01:03 -0700350 private static native void nPauseSurface(long nativeProxy, Surface window);
Chris Craik797b95b2014-05-20 18:10:25 -0700351 private static native void nSetup(long nativeProxy, int width, int height,
352 float lightX, float lightY, float lightZ, float lightRadius);
John Reck63a06672014-05-07 13:45:54 -0700353 private static native void nSetOpaque(long nativeProxy, boolean opaque);
John Reckf9be7792014-05-02 18:21:16 -0700354 private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
John Reck4f02bf42014-01-03 18:09:17 -0800355 int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
John Reckfc53ef272014-02-11 10:40:25 -0800356 private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
John Reckfae904d2014-04-14 11:01:57 -0700357 private static native void nDestroyCanvasAndSurface(long nativeProxy);
John Reck4f02bf42014-01-03 18:09:17 -0800358
John Reck0d1f6342014-03-28 20:30:27 -0700359 private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
John Reck19b6bcf2014-02-14 20:03:38 -0800360
361 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
362 private static native long nCreateTextureLayer(long nativeProxy);
363 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
364 private static native void nDestroyLayer(long nativeProxy, long layer);
John Reck28ad7b52014-04-07 16:59:25 -0700365
366 private static native void nFence(long nativeProxy);
John Reckcec24ae2013-11-05 13:27:50 -0800367}