ThreadedRenderer.java revision 86faf9ec3edc24a9d04548e151bca3a2510396a4
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 * TODO: Make draw() async. 37 * TODO: Figure out how to share the DisplayList between two threads (global lock?) 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 int mWidth, mHeight; 66 private long mNativeProxy; 67 private boolean mInitialized = false; 68 private RenderNode mRootNode; 69 private Choreographer mChoreographer; 70 71 ThreadedRenderer(boolean translucent) { 72 AtlasInitializer.sInstance.init(); 73 74 long rootNodePtr = nCreateRootRenderNode(); 75 mRootNode = RenderNode.adopt(rootNodePtr); 76 mRootNode.setClipToBounds(false); 77 mNativeProxy = nCreateProxy(translucent, rootNodePtr); 78 79 // Setup timing 80 mChoreographer = Choreographer.getInstance(); 81 nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos()); 82 } 83 84 @Override 85 void destroy(boolean full) { 86 mInitialized = false; 87 updateEnabledState(null); 88 nDestroyCanvasAndSurface(mNativeProxy); 89 } 90 91 private void updateEnabledState(Surface surface) { 92 if (surface == null || !surface.isValid()) { 93 setEnabled(false); 94 } else { 95 setEnabled(mInitialized); 96 } 97 } 98 99 @Override 100 boolean initialize(Surface surface) throws OutOfResourcesException { 101 mInitialized = true; 102 updateEnabledState(surface); 103 return nInitialize(mNativeProxy, surface); 104 } 105 106 @Override 107 void updateSurface(Surface surface) throws OutOfResourcesException { 108 updateEnabledState(surface); 109 nUpdateSurface(mNativeProxy, surface); 110 } 111 112 @Override 113 void pauseSurface(Surface surface) { 114 nPauseSurface(mNativeProxy, surface); 115 } 116 117 @Override 118 void destroyHardwareResources(View view) { 119 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 } 134 } 135 136 @Override 137 void invalidate(Surface surface) { 138 updateSurface(surface); 139 } 140 141 @Override 142 boolean safelyRun(Runnable action) { 143 nRunWithGlContext(mNativeProxy, action); 144 return true; 145 } 146 147 @Override 148 void setup(int width, int height) { 149 mWidth = width; 150 mHeight = height; 151 mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight); 152 nSetup(mNativeProxy, width, height); 153 } 154 155 @Override 156 void setOpaque(boolean opaque) { 157 nSetOpaque(mNativeProxy, opaque); 158 } 159 160 @Override 161 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() { 183 return nLoadSystemProperties(mNativeProxy); 184 } 185 186 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) { 187 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"); 194 HardwareCanvas canvas = mRootNode.start(mWidth, mHeight); 195 try { 196 canvas.save(); 197 callbacks.onHardwarePreDraw(canvas); 198 canvas.drawDisplayList(view.getDisplayList()); 199 callbacks.onHardwarePostDraw(canvas); 200 canvas.restore(); 201 } finally { 202 mRootNode.end(canvas); 203 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 204 } 205 206 view.mRecreateDisplayList = false; 207 } 208 209 @Override 210 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) { 211 attachInfo.mIgnoreDirtyState = true; 212 long frameTimeNanos = mChoreographer.getFrameTimeNanos(); 213 attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS; 214 215 updateRootDisplayList(view, callbacks); 216 217 attachInfo.mIgnoreDirtyState = false; 218 219 if (dirty == null) { 220 dirty = NULL_RECT; 221 } 222 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos, 223 dirty.left, dirty.top, dirty.right, dirty.bottom); 224 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) { 225 attachInfo.mViewRootImpl.invalidate(); 226 } 227 } 228 229 @Override 230 void invokeFunctor(long functor, boolean waitForCompletion) { 231 nInvokeFunctor(mNativeProxy, functor, waitForCompletion); 232 } 233 234 @Override 235 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 285 void setName(String name) { 286 } 287 288 @Override 289 void fence() { 290 nFence(mNativeProxy); 291 } 292 293 @Override 294 protected void finalize() throws Throwable { 295 try { 296 nDeleteProxy(mNativeProxy); 297 mNativeProxy = 0; 298 } finally { 299 super.finalize(); 300 } 301 } 302 303 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); 340 341 private static native long nCreateRootRenderNode(); 342 private static native long nCreateProxy(boolean translucent, long rootRenderNode); 343 private static native void nDeleteProxy(long nativeProxy); 344 345 private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos); 346 private static native boolean nLoadSystemProperties(long nativeProxy); 347 348 private static native boolean nInitialize(long nativeProxy, Surface window); 349 private static native void nUpdateSurface(long nativeProxy, Surface window); 350 private static native void nPauseSurface(long nativeProxy, Surface window); 351 private static native void nSetup(long nativeProxy, int width, int height); 352 private static native void nSetOpaque(long nativeProxy, boolean opaque); 353 private static native void nSetDisplayListData(long nativeProxy, long displayList, 354 long newData); 355 private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos, 356 int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); 357 private static native void nRunWithGlContext(long nativeProxy, Runnable runnable); 358 private static native void nDestroyCanvasAndSurface(long nativeProxy); 359 360 private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion); 361 362 private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height); 363 private static native long nCreateTextureLayer(long nativeProxy); 364 private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap); 365 private static native void nDestroyLayer(long nativeProxy, long layer); 366 367 private static native void nFence(long nativeProxy); 368} 369