ThreadedRenderer.java revision b8802b1293c05a14399005aeaeb93b82ec2e2f27
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 return nInitialize(mNativeProxy, surface); 117 } 118 119 @Override 120 void updateSurface(Surface surface) throws OutOfResourcesException { 121 updateEnabledState(surface); 122 nUpdateSurface(mNativeProxy, surface); 123 } 124 125 @Override 126 void pauseSurface(Surface surface) { 127 nPauseSurface(mNativeProxy, surface); 128 } 129 130 @Override 131 void destroyHardwareResources(View view) { 132 destroyResources(view); 133 nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS); 134 } 135 136 private static void destroyResources(View view) { 137 view.destroyHardwareResources(); 138 139 if (view instanceof ViewGroup) { 140 ViewGroup group = (ViewGroup) view; 141 142 int count = group.getChildCount(); 143 for (int i = 0; i < count; i++) { 144 destroyResources(group.getChildAt(i)); 145 } 146 } 147 } 148 149 @Override 150 void invalidate(Surface surface) { 151 updateSurface(surface); 152 } 153 154 @Override 155 boolean safelyRun(Runnable action) { 156 nRunWithGlContext(mNativeProxy, action); 157 return true; 158 } 159 160 @Override 161 void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) { 162 mWidth = width; 163 mHeight = height; 164 mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight); 165 nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius); 166 } 167 168 @Override 169 void setOpaque(boolean opaque) { 170 nSetOpaque(mNativeProxy, opaque); 171 } 172 173 @Override 174 int getWidth() { 175 return mWidth; 176 } 177 178 @Override 179 int getHeight() { 180 return mHeight; 181 } 182 183 @Override 184 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) { 185 pw.flush(); 186 nDumpProfileInfo(mNativeProxy, fd); 187 } 188 189 private static int search(String[] values, String value) { 190 for (int i = 0; i < values.length; i++) { 191 if (values[i].equals(value)) return i; 192 } 193 return -1; 194 } 195 196 private static boolean checkIfProfilingRequested() { 197 String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY); 198 int graphType = search(VISUALIZERS, profiling); 199 return (graphType >= 0) || Boolean.parseBoolean(profiling); 200 } 201 202 @Override 203 boolean loadSystemProperties() { 204 boolean changed = nLoadSystemProperties(mNativeProxy); 205 boolean wantProfiling = checkIfProfilingRequested(); 206 if (wantProfiling != mProfilingEnabled) { 207 mProfilingEnabled = wantProfiling; 208 changed = true; 209 } 210 return changed; 211 } 212 213 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) { 214 view.mPrivateFlags |= View.PFLAG_DRAWN; 215 216 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) 217 == View.PFLAG_INVALIDATED; 218 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; 219 220 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); 221 HardwareCanvas canvas = mRootNode.start(mWidth, mHeight); 222 try { 223 canvas.save(); 224 callbacks.onHardwarePreDraw(canvas); 225 canvas.drawDisplayList(view.getDisplayList()); 226 callbacks.onHardwarePostDraw(canvas); 227 canvas.restore(); 228 } finally { 229 mRootNode.end(canvas); 230 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 231 } 232 233 view.mRecreateDisplayList = false; 234 } 235 236 @Override 237 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) { 238 attachInfo.mIgnoreDirtyState = true; 239 long frameTimeNanos = mChoreographer.getFrameTimeNanos(); 240 attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS; 241 242 long recordDuration = 0; 243 if (mProfilingEnabled) { 244 recordDuration = System.nanoTime(); 245 } 246 247 updateRootDisplayList(view, callbacks); 248 249 if (mProfilingEnabled) { 250 recordDuration = System.nanoTime() - recordDuration; 251 } 252 253 attachInfo.mIgnoreDirtyState = false; 254 255 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos, 256 recordDuration, view.getResources().getDisplayMetrics().density); 257 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) { 258 attachInfo.mViewRootImpl.invalidate(); 259 } 260 } 261 262 @Override 263 void invokeFunctor(long functor, boolean waitForCompletion) { 264 nInvokeFunctor(mNativeProxy, functor, waitForCompletion); 265 } 266 267 @Override 268 HardwareLayer createTextureLayer() { 269 long layer = nCreateTextureLayer(mNativeProxy); 270 return HardwareLayer.adoptTextureLayer(this, layer); 271 } 272 273 @Override 274 SurfaceTexture createSurfaceTexture(final HardwareLayer layer) { 275 final SurfaceTexture[] ret = new SurfaceTexture[1]; 276 nRunWithGlContext(mNativeProxy, new Runnable() { 277 @Override 278 public void run() { 279 ret[0] = layer.createSurfaceTexture(); 280 } 281 }); 282 return ret[0]; 283 } 284 285 @Override 286 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) { 287 return nCopyLayerInto(mNativeProxy, 288 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap); 289 } 290 291 @Override 292 void pushLayerUpdate(HardwareLayer layer) { 293 nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); 294 } 295 296 @Override 297 void flushLayerUpdates() { 298 // TODO: Figure out what this should do or remove it 299 } 300 301 @Override 302 void onLayerDestroyed(HardwareLayer layer) { 303 nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); 304 } 305 306 @Override 307 void setName(String name) { 308 } 309 310 @Override 311 void fence() { 312 nFence(mNativeProxy); 313 } 314 315 @Override 316 public void notifyFramePending() { 317 nNotifyFramePending(mNativeProxy); 318 } 319 320 @Override 321 protected void finalize() throws Throwable { 322 try { 323 nDeleteProxy(mNativeProxy); 324 mNativeProxy = 0; 325 } finally { 326 super.finalize(); 327 } 328 } 329 330 static void startTrimMemory(int level) { 331 // TODO 332 } 333 334 static void endTrimMemory() { 335 // TODO 336 } 337 338 private static class AtlasInitializer { 339 static AtlasInitializer sInstance = new AtlasInitializer(); 340 341 private boolean mInitialized = false; 342 343 private AtlasInitializer() {} 344 345 synchronized void init(Context context) { 346 if (mInitialized) return; 347 IBinder binder = ServiceManager.getService("assetatlas"); 348 if (binder == null) return; 349 350 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder); 351 try { 352 if (atlas.isCompatible(android.os.Process.myPpid())) { 353 GraphicBuffer buffer = atlas.getBuffer(); 354 if (buffer != null) { 355 long[] map = atlas.getMap(); 356 if (map != null) { 357 // TODO Remove after fixing b/15425820 358 validateMap(context, map); 359 nSetAtlas(buffer, map); 360 mInitialized = true; 361 } 362 // If IAssetAtlas is not the same class as the IBinder 363 // we are using a remote service and we can safely 364 // destroy the graphic buffer 365 if (atlas.getClass() != binder.getClass()) { 366 buffer.destroy(); 367 } 368 } 369 } 370 } catch (RemoteException e) { 371 Log.w(LOG_TAG, "Could not acquire atlas", e); 372 } 373 } 374 375 private static void validateMap(Context context, long[] map) { 376 Log.d("Atlas", "Validating map..."); 377 HashSet<Long> preloadedPointers = new HashSet<Long>(); 378 379 // We only care about drawables that hold bitmaps 380 final Resources resources = context.getResources(); 381 final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables(); 382 383 final int count = drawables.size(); 384 for (int i = 0; i < count; i++) { 385 final Bitmap bitmap = drawables.valueAt(i).getBitmap(); 386 if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) { 387 preloadedPointers.add(bitmap.mNativeBitmap); 388 } 389 } 390 391 for (int i = 0; i < map.length; i += 4) { 392 if (!preloadedPointers.contains(map[i])) { 393 Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i])); 394 map[i] = 0; 395 } 396 } 397 } 398 } 399 400 static native void setupShadersDiskCache(String cacheFile); 401 402 private static native void nSetAtlas(GraphicBuffer buffer, long[] map); 403 404 private static native long nCreateRootRenderNode(); 405 private static native long nCreateProxy(boolean translucent, long rootRenderNode); 406 private static native void nDeleteProxy(long nativeProxy); 407 408 private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos); 409 private static native boolean nLoadSystemProperties(long nativeProxy); 410 411 private static native boolean nInitialize(long nativeProxy, Surface window); 412 private static native void nUpdateSurface(long nativeProxy, Surface window); 413 private static native void nPauseSurface(long nativeProxy, Surface window); 414 private static native void nSetup(long nativeProxy, int width, int height, 415 float lightX, float lightY, float lightZ, float lightRadius); 416 private static native void nSetOpaque(long nativeProxy, boolean opaque); 417 private static native int nSyncAndDrawFrame(long nativeProxy, 418 long frameTimeNanos, long recordDuration, float density); 419 private static native void nRunWithGlContext(long nativeProxy, Runnable runnable); 420 private static native void nDestroyCanvasAndSurface(long nativeProxy); 421 422 private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion); 423 424 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height); 425 private static native long nCreateTextureLayer(long nativeProxy); 426 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap); 427 private static native void nPushLayerUpdate(long nativeProxy, long layer); 428 private static native void nCancelLayerUpdate(long nativeProxy, long layer); 429 430 private static native void nFlushCaches(long nativeProxy, int flushMode); 431 432 private static native void nFence(long nativeProxy); 433 private static native void nNotifyFramePending(long nativeProxy); 434 435 private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd); 436} 437