ThreadedRenderer.java revision 5795d6408d8bf44ffe2f49a25f9f333069b59a49
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.content.Context; 20import android.content.res.Resources; 21import android.graphics.Bitmap; 22import android.graphics.Rect; 23import android.graphics.SurfaceTexture; 24import android.graphics.drawable.Drawable; 25import android.os.IBinder; 26import android.os.RemoteException; 27import android.os.ServiceManager; 28import android.os.SystemProperties; 29import android.os.Trace; 30import android.util.Log; 31import android.util.LongSparseArray; 32import android.util.TimeUtils; 33import android.view.Surface.OutOfResourcesException; 34import android.view.View.AttachInfo; 35 36import java.io.FileDescriptor; 37import java.io.PrintWriter; 38import java.util.ArrayList; 39import java.util.Collections; 40import java.util.Comparator; 41import java.util.HashSet; 42 43/** 44 * Hardware renderer that proxies the rendering to a render thread. Most calls 45 * are currently synchronous. 46 * 47 * The UI thread can block on the RenderThread, but RenderThread must never 48 * block on the UI thread. 49 * 50 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates 51 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed 52 * by the lifecycle of the RenderProxy. 53 * 54 * Note that although currently the EGL context & surfaces are created & managed 55 * by the render thread, the goal is to move that into a shared structure that can 56 * be managed by both threads. EGLSurface creation & deletion should ideally be 57 * done on the UI thread and not the RenderThread to avoid stalling the 58 * RenderThread with surface buffer allocation. 59 * 60 * @hide 61 */ 62public class ThreadedRenderer extends HardwareRenderer { 63 private static final String LOGTAG = "ThreadedRenderer"; 64 65 // Keep in sync with DrawFrameTask.h SYNC_* flags 66 // Nothing interesting to report 67 private static final int SYNC_OK = 0x0; 68 // Needs a ViewRoot invalidate 69 private static final int SYNC_INVALIDATE_REQUIRED = 0x1; 70 71 private static final String[] VISUALIZERS = { 72 PROFILE_PROPERTY_VISUALIZE_BARS, 73 }; 74 75 private int mWidth, mHeight; 76 private long mNativeProxy; 77 private boolean mInitialized = false; 78 private RenderNode mRootNode; 79 private Choreographer mChoreographer; 80 private boolean mProfilingEnabled; 81 82 ThreadedRenderer(Context context, boolean translucent) { 83 AtlasInitializer.sInstance.init(context); 84 85 long rootNodePtr = nCreateRootRenderNode(); 86 mRootNode = RenderNode.adopt(rootNodePtr); 87 mRootNode.setClipToBounds(false); 88 mNativeProxy = nCreateProxy(translucent, rootNodePtr); 89 90 // Setup timing 91 mChoreographer = Choreographer.getInstance(); 92 nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos()); 93 94 loadSystemProperties(); 95 } 96 97 @Override 98 void destroy(boolean full) { 99 mInitialized = false; 100 updateEnabledState(null); 101 nDestroyCanvasAndSurface(mNativeProxy); 102 } 103 104 private void updateEnabledState(Surface surface) { 105 if (surface == null || !surface.isValid()) { 106 setEnabled(false); 107 } else { 108 setEnabled(mInitialized); 109 } 110 } 111 112 @Override 113 boolean initialize(Surface surface) throws OutOfResourcesException { 114 mInitialized = true; 115 updateEnabledState(surface); 116 boolean status = nInitialize(mNativeProxy, surface); 117 surface.allocateBuffers(); 118 return status; 119 } 120 121 @Override 122 void updateSurface(Surface surface) throws OutOfResourcesException { 123 updateEnabledState(surface); 124 nUpdateSurface(mNativeProxy, surface); 125 } 126 127 @Override 128 void pauseSurface(Surface surface) { 129 nPauseSurface(mNativeProxy, surface); 130 } 131 132 @Override 133 void destroyHardwareResources(View view) { 134 destroyResources(view); 135 nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS); 136 } 137 138 private static void destroyResources(View view) { 139 view.destroyHardwareResources(); 140 141 if (view instanceof ViewGroup) { 142 ViewGroup group = (ViewGroup) view; 143 144 int count = group.getChildCount(); 145 for (int i = 0; i < count; i++) { 146 destroyResources(group.getChildAt(i)); 147 } 148 } 149 } 150 151 @Override 152 void invalidate(Surface surface) { 153 updateSurface(surface); 154 } 155 156 @Override 157 boolean safelyRun(Runnable action) { 158 nRunWithGlContext(mNativeProxy, action); 159 return true; 160 } 161 162 @Override 163 void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) { 164 mWidth = width; 165 mHeight = height; 166 mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight); 167 nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius); 168 } 169 170 @Override 171 void setOpaque(boolean opaque) { 172 nSetOpaque(mNativeProxy, opaque); 173 } 174 175 @Override 176 int getWidth() { 177 return mWidth; 178 } 179 180 @Override 181 int getHeight() { 182 return mHeight; 183 } 184 185 @Override 186 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) { 187 pw.flush(); 188 nDumpProfileInfo(mNativeProxy, fd); 189 } 190 191 private static int search(String[] values, String value) { 192 for (int i = 0; i < values.length; i++) { 193 if (values[i].equals(value)) return i; 194 } 195 return -1; 196 } 197 198 private static boolean checkIfProfilingRequested() { 199 String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY); 200 int graphType = search(VISUALIZERS, profiling); 201 return (graphType >= 0) || Boolean.parseBoolean(profiling); 202 } 203 204 @Override 205 boolean loadSystemProperties() { 206 boolean changed = nLoadSystemProperties(mNativeProxy); 207 boolean wantProfiling = checkIfProfilingRequested(); 208 if (wantProfiling != mProfilingEnabled) { 209 mProfilingEnabled = wantProfiling; 210 changed = true; 211 } 212 return changed; 213 } 214 215 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) { 216 view.mPrivateFlags |= View.PFLAG_DRAWN; 217 218 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) 219 == View.PFLAG_INVALIDATED; 220 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; 221 222 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); 223 HardwareCanvas canvas = mRootNode.start(mWidth, mHeight); 224 try { 225 canvas.save(); 226 callbacks.onHardwarePreDraw(canvas); 227 canvas.drawDisplayList(view.getDisplayList()); 228 callbacks.onHardwarePostDraw(canvas); 229 canvas.restore(); 230 } finally { 231 mRootNode.end(canvas); 232 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 233 } 234 235 view.mRecreateDisplayList = false; 236 } 237 238 @Override 239 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) { 240 attachInfo.mIgnoreDirtyState = true; 241 long frameTimeNanos = mChoreographer.getFrameTimeNanos(); 242 attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS; 243 244 long recordDuration = 0; 245 if (mProfilingEnabled) { 246 recordDuration = System.nanoTime(); 247 } 248 249 updateRootDisplayList(view, callbacks); 250 251 if (mProfilingEnabled) { 252 recordDuration = System.nanoTime() - recordDuration; 253 } 254 255 attachInfo.mIgnoreDirtyState = false; 256 257 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos, 258 recordDuration, view.getResources().getDisplayMetrics().density); 259 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) { 260 attachInfo.mViewRootImpl.invalidate(); 261 } 262 } 263 264 @Override 265 void invokeFunctor(long functor, boolean waitForCompletion) { 266 nInvokeFunctor(mNativeProxy, functor, waitForCompletion); 267 } 268 269 @Override 270 HardwareLayer createTextureLayer() { 271 long layer = nCreateTextureLayer(mNativeProxy); 272 return HardwareLayer.adoptTextureLayer(this, layer); 273 } 274 275 @Override 276 SurfaceTexture createSurfaceTexture(final HardwareLayer layer) { 277 final SurfaceTexture[] ret = new SurfaceTexture[1]; 278 nRunWithGlContext(mNativeProxy, new Runnable() { 279 @Override 280 public void run() { 281 ret[0] = layer.createSurfaceTexture(); 282 } 283 }); 284 return ret[0]; 285 } 286 287 @Override 288 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) { 289 return nCopyLayerInto(mNativeProxy, 290 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap); 291 } 292 293 @Override 294 void pushLayerUpdate(HardwareLayer layer) { 295 nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); 296 } 297 298 @Override 299 void flushLayerUpdates() { 300 // TODO: Figure out what this should do or remove it 301 } 302 303 @Override 304 void onLayerDestroyed(HardwareLayer layer) { 305 nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); 306 } 307 308 @Override 309 void setName(String name) { 310 } 311 312 @Override 313 void fence() { 314 nFence(mNativeProxy); 315 } 316 317 @Override 318 public void notifyFramePending() { 319 nNotifyFramePending(mNativeProxy); 320 } 321 322 @Override 323 protected void finalize() throws Throwable { 324 try { 325 nDeleteProxy(mNativeProxy); 326 mNativeProxy = 0; 327 } finally { 328 super.finalize(); 329 } 330 } 331 332 static void startTrimMemory(int level) { 333 // TODO 334 } 335 336 static void endTrimMemory() { 337 // TODO 338 } 339 340 private static class AtlasInitializer { 341 static AtlasInitializer sInstance = new AtlasInitializer(); 342 343 private boolean mInitialized = false; 344 345 private AtlasInitializer() {} 346 347 synchronized void init(Context context) { 348 if (mInitialized) return; 349 IBinder binder = ServiceManager.getService("assetatlas"); 350 if (binder == null) return; 351 352 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder); 353 try { 354 if (atlas.isCompatible(android.os.Process.myPpid())) { 355 GraphicBuffer buffer = atlas.getBuffer(); 356 if (buffer != null) { 357 long[] map = atlas.getMap(); 358 if (map != null) { 359 // TODO Remove after fixing b/15425820 360 validateMap(context, map); 361 nSetAtlas(buffer, map); 362 mInitialized = true; 363 } 364 // If IAssetAtlas is not the same class as the IBinder 365 // we are using a remote service and we can safely 366 // destroy the graphic buffer 367 if (atlas.getClass() != binder.getClass()) { 368 buffer.destroy(); 369 } 370 } 371 } 372 } catch (RemoteException e) { 373 Log.w(LOG_TAG, "Could not acquire atlas", e); 374 } 375 } 376 377 private static void validateMap(Context context, long[] map) { 378 Log.d("Atlas", "Validating map..."); 379 HashSet<Long> preloadedPointers = new HashSet<Long>(); 380 381 // We only care about drawables that hold bitmaps 382 final Resources resources = context.getResources(); 383 final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables(); 384 385 final int count = drawables.size(); 386 for (int i = 0; i < count; i++) { 387 final Bitmap bitmap = drawables.valueAt(i).getBitmap(); 388 if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) { 389 preloadedPointers.add(bitmap.mNativeBitmap); 390 } 391 } 392 393 for (int i = 0; i < map.length; i += 4) { 394 if (!preloadedPointers.contains(map[i])) { 395 Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i])); 396 map[i] = 0; 397 } 398 } 399 } 400 } 401 402 static native void setupShadersDiskCache(String cacheFile); 403 404 private static native void nSetAtlas(GraphicBuffer buffer, long[] map); 405 406 private static native long nCreateRootRenderNode(); 407 private static native long nCreateProxy(boolean translucent, long rootRenderNode); 408 private static native void nDeleteProxy(long nativeProxy); 409 410 private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos); 411 private static native boolean nLoadSystemProperties(long nativeProxy); 412 413 private static native boolean nInitialize(long nativeProxy, Surface window); 414 private static native void nUpdateSurface(long nativeProxy, Surface window); 415 private static native void nPauseSurface(long nativeProxy, Surface window); 416 private static native void nSetup(long nativeProxy, int width, int height, 417 float lightX, float lightY, float lightZ, float lightRadius); 418 private static native void nSetOpaque(long nativeProxy, boolean opaque); 419 private static native int nSyncAndDrawFrame(long nativeProxy, 420 long frameTimeNanos, long recordDuration, float density); 421 private static native void nRunWithGlContext(long nativeProxy, Runnable runnable); 422 private static native void nDestroyCanvasAndSurface(long nativeProxy); 423 424 private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion); 425 426 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height); 427 private static native long nCreateTextureLayer(long nativeProxy); 428 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap); 429 private static native void nPushLayerUpdate(long nativeProxy, long layer); 430 private static native void nCancelLayerUpdate(long nativeProxy, long layer); 431 432 private static native void nFlushCaches(long nativeProxy, int flushMode); 433 434 private static native void nFence(long nativeProxy); 435 private static native void nNotifyFramePending(long nativeProxy); 436 437 private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd); 438} 439