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