ThreadedRenderer.java revision e1628b7c6fc3822fa83cf02028ce8ad67abb0afe
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.Trace; 26import android.util.Log; 27import android.util.TimeUtils; 28import android.view.Surface.OutOfResourcesException; 29import android.view.View.AttachInfo; 30 31import java.io.PrintWriter; 32 33/** 34 * Hardware renderer that proxies the rendering to a render thread. Most calls 35 * are currently synchronous. 36 * 37 * The UI thread can block on the RenderThread, but RenderThread must never 38 * block on the UI thread. 39 * 40 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates 41 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed 42 * by the lifecycle of the RenderProxy. 43 * 44 * Note that although currently the EGL context & surfaces are created & managed 45 * by the render thread, the goal is to move that into a shared structure that can 46 * be managed by both threads. EGLSurface creation & deletion should ideally be 47 * done on the UI thread and not the RenderThread to avoid stalling the 48 * RenderThread with surface buffer allocation. 49 * 50 * @hide 51 */ 52public class ThreadedRenderer extends HardwareRenderer { 53 private static final String LOGTAG = "ThreadedRenderer"; 54 55 private static final Rect NULL_RECT = new Rect(); 56 57 // Keep in sync with DrawFrameTask.h SYNC_* flags 58 // Nothing interesting to report 59 private static final int SYNC_OK = 0x0; 60 // Needs a ViewRoot invalidate 61 private static final int SYNC_INVALIDATE_REQUIRED = 0x1; 62 63 private int mWidth, mHeight; 64 private long mNativeProxy; 65 private boolean mInitialized = false; 66 private RenderNode mRootNode; 67 private Choreographer mChoreographer; 68 69 ThreadedRenderer(boolean translucent) { 70 AtlasInitializer.sInstance.init(); 71 72 long rootNodePtr = nCreateRootRenderNode(); 73 mRootNode = RenderNode.adopt(rootNodePtr); 74 mRootNode.setClipToBounds(false); 75 mNativeProxy = nCreateProxy(translucent, rootNodePtr); 76 77 // Setup timing 78 mChoreographer = Choreographer.getInstance(); 79 nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos()); 80 } 81 82 @Override 83 void destroy(boolean full) { 84 mInitialized = false; 85 updateEnabledState(null); 86 nDestroyCanvasAndSurface(mNativeProxy); 87 } 88 89 private void updateEnabledState(Surface surface) { 90 if (surface == null || !surface.isValid()) { 91 setEnabled(false); 92 } else { 93 setEnabled(mInitialized); 94 } 95 } 96 97 @Override 98 boolean initialize(Surface surface) throws OutOfResourcesException { 99 mInitialized = true; 100 updateEnabledState(surface); 101 return nInitialize(mNativeProxy, surface); 102 } 103 104 @Override 105 void updateSurface(Surface surface) throws OutOfResourcesException { 106 updateEnabledState(surface); 107 nUpdateSurface(mNativeProxy, surface); 108 } 109 110 @Override 111 void pauseSurface(Surface surface) { 112 nPauseSurface(mNativeProxy, surface); 113 } 114 115 @Override 116 void destroyHardwareResources(View view) { 117 destroyResources(view); 118 nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS); 119 } 120 121 private static void destroyResources(View view) { 122 view.destroyHardwareResources(); 123 124 if (view instanceof ViewGroup) { 125 ViewGroup group = (ViewGroup) view; 126 127 int count = group.getChildCount(); 128 for (int i = 0; i < count; i++) { 129 destroyResources(group.getChildAt(i)); 130 } 131 } 132 } 133 134 @Override 135 void invalidate(Surface surface) { 136 updateSurface(surface); 137 } 138 139 @Override 140 boolean safelyRun(Runnable action) { 141 nRunWithGlContext(mNativeProxy, action); 142 return true; 143 } 144 145 @Override 146 void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) { 147 mWidth = width; 148 mHeight = height; 149 mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight); 150 nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius); 151 } 152 153 @Override 154 void setOpaque(boolean opaque) { 155 nSetOpaque(mNativeProxy, opaque); 156 } 157 158 @Override 159 int getWidth() { 160 return mWidth; 161 } 162 163 @Override 164 int getHeight() { 165 return mHeight; 166 } 167 168 @Override 169 void dumpGfxInfo(PrintWriter pw) { 170 // TODO Auto-generated method stub 171 } 172 173 @Override 174 long getFrameCount() { 175 // TODO Auto-generated method stub 176 return 0; 177 } 178 179 @Override 180 boolean loadSystemProperties() { 181 return nLoadSystemProperties(mNativeProxy); 182 } 183 184 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) { 185 view.mPrivateFlags |= View.PFLAG_DRAWN; 186 187 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) 188 == View.PFLAG_INVALIDATED; 189 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; 190 191 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); 192 HardwareCanvas canvas = mRootNode.start(mWidth, mHeight); 193 try { 194 canvas.save(); 195 callbacks.onHardwarePreDraw(canvas); 196 canvas.drawDisplayList(view.getDisplayList()); 197 callbacks.onHardwarePostDraw(canvas); 198 canvas.restore(); 199 } finally { 200 mRootNode.end(canvas); 201 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 202 } 203 204 view.mRecreateDisplayList = false; 205 } 206 207 @Override 208 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) { 209 attachInfo.mIgnoreDirtyState = true; 210 long frameTimeNanos = mChoreographer.getFrameTimeNanos(); 211 attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS; 212 213 updateRootDisplayList(view, callbacks); 214 215 attachInfo.mIgnoreDirtyState = false; 216 217 if (dirty == null) { 218 dirty = NULL_RECT; 219 } 220 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos, 221 dirty.left, dirty.top, dirty.right, dirty.bottom); 222 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) { 223 attachInfo.mViewRootImpl.invalidate(); 224 } 225 } 226 227 @Override 228 void invokeFunctor(long functor, boolean waitForCompletion) { 229 nInvokeFunctor(mNativeProxy, functor, waitForCompletion); 230 } 231 232 @Override 233 HardwareLayer createDisplayListLayer(int width, int height) { 234 long layer = nCreateDisplayListLayer(mNativeProxy, width, height); 235 return HardwareLayer.adoptDisplayListLayer(this, layer); 236 } 237 238 @Override 239 HardwareLayer createTextureLayer() { 240 long layer = nCreateTextureLayer(mNativeProxy); 241 return HardwareLayer.adoptTextureLayer(this, layer); 242 } 243 244 @Override 245 SurfaceTexture createSurfaceTexture(final HardwareLayer layer) { 246 final SurfaceTexture[] ret = new SurfaceTexture[1]; 247 nRunWithGlContext(mNativeProxy, new Runnable() { 248 @Override 249 public void run() { 250 ret[0] = layer.createSurfaceTexture(); 251 } 252 }); 253 return ret[0]; 254 } 255 256 @Override 257 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) { 258 return nCopyLayerInto(mNativeProxy, 259 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap); 260 } 261 262 @Override 263 void pushLayerUpdate(HardwareLayer layer) { 264 // TODO: Remove this, it's not needed outside of GLRenderer 265 } 266 267 @Override 268 void onLayerCreated(HardwareLayer layer) { 269 // TODO: Is this actually useful? 270 } 271 272 @Override 273 void flushLayerUpdates() { 274 // TODO: Figure out what this should do or remove it 275 } 276 277 @Override 278 void onLayerDestroyed(HardwareLayer layer) { 279 nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater()); 280 } 281 282 @Override 283 void setName(String name) { 284 } 285 286 @Override 287 void fence() { 288 nFence(mNativeProxy); 289 } 290 291 @Override 292 public void notifyFramePending() { 293 nNotifyFramePending(mNativeProxy); 294 } 295 296 @Override 297 protected void finalize() throws Throwable { 298 try { 299 nDeleteProxy(mNativeProxy); 300 mNativeProxy = 0; 301 } finally { 302 super.finalize(); 303 } 304 } 305 306 private static class AtlasInitializer { 307 static AtlasInitializer sInstance = new AtlasInitializer(); 308 309 private boolean mInitialized = false; 310 311 private AtlasInitializer() {} 312 313 synchronized void init() { 314 if (mInitialized) return; 315 IBinder binder = ServiceManager.getService("assetatlas"); 316 if (binder == null) return; 317 318 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder); 319 try { 320 if (atlas.isCompatible(android.os.Process.myPpid())) { 321 GraphicBuffer buffer = atlas.getBuffer(); 322 if (buffer != null) { 323 long[] map = atlas.getMap(); 324 if (map != null) { 325 nSetAtlas(buffer, map); 326 mInitialized = true; 327 } 328 // If IAssetAtlas is not the same class as the IBinder 329 // we are using a remote service and we can safely 330 // destroy the graphic buffer 331 if (atlas.getClass() != binder.getClass()) { 332 buffer.destroy(); 333 } 334 } 335 } 336 } catch (RemoteException e) { 337 Log.w(LOG_TAG, "Could not acquire atlas", e); 338 } 339 } 340 } 341 342 private static native void nSetAtlas(GraphicBuffer buffer, long[] map); 343 344 private static native long nCreateRootRenderNode(); 345 private static native long nCreateProxy(boolean translucent, long rootRenderNode); 346 private static native void nDeleteProxy(long nativeProxy); 347 348 private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos); 349 private static native boolean nLoadSystemProperties(long nativeProxy); 350 351 private static native boolean nInitialize(long nativeProxy, Surface window); 352 private static native void nUpdateSurface(long nativeProxy, Surface window); 353 private static native void nPauseSurface(long nativeProxy, Surface window); 354 private static native void nSetup(long nativeProxy, int width, int height, 355 float lightX, float lightY, float lightZ, float lightRadius); 356 private static native void nSetOpaque(long nativeProxy, boolean opaque); 357 private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos, 358 int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); 359 private static native void nRunWithGlContext(long nativeProxy, Runnable runnable); 360 private static native void nDestroyCanvasAndSurface(long nativeProxy); 361 362 private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion); 363 364 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height); 365 private static native long nCreateTextureLayer(long nativeProxy); 366 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap); 367 private static native void nDestroyLayer(long nativeProxy, long layer); 368 369 private static native void nFlushCaches(long nativeProxy, int flushMode); 370 371 private static native void nFence(long nativeProxy); 372 private static native void nNotifyFramePending(long nativeProxy); 373} 374