FileDocCategorySizeDatePackage
ThreadedRenderer.javaAPI DocAndroid 5.1 API19048Thu Mar 12 22:22:10 GMT 2015android.view

ThreadedRenderer

public class ThreadedRenderer extends HardwareRenderer
Hardware renderer that proxies the rendering to a render thread. Most calls are currently synchronous. The UI thread can block on the RenderThread, but RenderThread must never block on the UI thread. ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed by the lifecycle of the RenderProxy. Note that although currently the EGL context & surfaces are created & managed by the render thread, the goal is to move that into a shared structure that can be managed by both threads. EGLSurface creation & deletion should ideally be done on the UI thread and not the RenderThread to avoid stalling the RenderThread with surface buffer allocation.
hide

Fields Summary
private static final String
LOGTAG
private static final int
SYNC_OK
private static final int
SYNC_INVALIDATE_REQUIRED
private static final int
SYNC_LOST_SURFACE_REWARD_IF_FOUND
private static final String[]
VISUALIZERS
private int
mWidth
private int
mHeight
private int
mSurfaceWidth
private int
mSurfaceHeight
private int
mInsetTop
private int
mInsetLeft
private boolean
mHasInsets
private final float
mLightY
private final float
mLightZ
private final float
mLightRadius
private final int
mAmbientShadowAlpha
private final int
mSpotShadowAlpha
private long
mNativeProxy
private boolean
mInitialized
private RenderNode
mRootNode
private Choreographer
mChoreographer
private boolean
mProfilingEnabled
private boolean
mRootNodeNeedsUpdate
Constructors Summary
ThreadedRenderer(android.content.Context context, boolean translucent)


        
        final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
        mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
        mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
        mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
        mAmbientShadowAlpha =
                (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
        mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
        a.recycle();

        long rootNodePtr = nCreateRootRenderNode();
        mRootNode = RenderNode.adopt(rootNodePtr);
        mRootNode.setClipToBounds(false);
        mNativeProxy = nCreateProxy(translucent, rootNodePtr);

        AtlasInitializer.sInstance.init(context, mNativeProxy);

        // Setup timing
        mChoreographer = Choreographer.getInstance();
        nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());

        loadSystemProperties();
    
Methods Summary
voidbuildLayer(RenderNode node)

        nBuildLayer(mNativeProxy, node.getNativeDisplayList());
    
private static booleancheckIfProfilingRequested()

        String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY);
        int graphType = search(VISUALIZERS, profiling);
        return (graphType >= 0) || Boolean.parseBoolean(profiling);
    
booleancopyLayerInto(HardwareLayer layer, android.graphics.Bitmap bitmap)

        return nCopyLayerInto(mNativeProxy,
                layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
    
HardwareLayercreateTextureLayer()

        long layer = nCreateTextureLayer(mNativeProxy);
        return HardwareLayer.adoptTextureLayer(this, layer);
    
voiddestroy()

        mInitialized = false;
        updateEnabledState(null);
        nDestroy(mNativeProxy);
    
voiddestroyHardwareResources(View view)

        destroyResources(view);
        nDestroyHardwareResources(mNativeProxy);
    
private static voiddestroyResources(View view)

        view.destroyHardwareResources();

        if (view instanceof ViewGroup) {
            ViewGroup group = (ViewGroup) view;

            int count = group.getChildCount();
            for (int i = 0; i < count; i++) {
                destroyResources(group.getChildAt(i));
            }
        }
    
voiddetachSurfaceTexture(long hardwareLayer)

        nDetachSurfaceTexture(mNativeProxy, hardwareLayer);
    
voiddraw(View view, android.view.View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks)

        attachInfo.mIgnoreDirtyState = true;
        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
        attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;

        long recordDuration = 0;
        if (mProfilingEnabled) {
            recordDuration = System.nanoTime();
        }

        updateRootDisplayList(view, callbacks);

        if (mProfilingEnabled) {
            recordDuration = System.nanoTime() - recordDuration;
        }

        attachInfo.mIgnoreDirtyState = false;

        // register animating rendernodes which started animating prior to renderer
        // creation, which is typical for animators started prior to first draw
        if (attachInfo.mPendingAnimatingRenderNodes != null) {
            final int count = attachInfo.mPendingAnimatingRenderNodes.size();
            for (int i = 0; i < count; i++) {
                registerAnimatingRenderNode(
                        attachInfo.mPendingAnimatingRenderNodes.get(i));
            }
            attachInfo.mPendingAnimatingRenderNodes.clear();
            // We don't need this anymore as subsequent calls to
            // ViewRootImpl#attachRenderNodeAnimator will go directly to us.
            attachInfo.mPendingAnimatingRenderNodes = null;
        }

        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
                recordDuration, view.getResources().getDisplayMetrics().density);
        if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
            setEnabled(false);
            attachInfo.mViewRootImpl.mSurface.release();
            // Invalidate since we failed to draw. This should fetch a Surface
            // if it is still needed or do nothing if we are no longer drawing
            attachInfo.mViewRootImpl.invalidate();
        }
        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
            attachInfo.mViewRootImpl.invalidate();
        }
    
voiddumpGfxInfo(java.io.PrintWriter pw, java.io.FileDescriptor fd)

        pw.flush();
        nDumpProfileInfo(mNativeProxy, fd);
    
voidfence()

        nFence(mNativeProxy);
    
protected voidfinalize()

        try {
            nDeleteProxy(mNativeProxy);
            mNativeProxy = 0;
        } finally {
            super.finalize();
        }
    
intgetHeight()

        return mHeight;
    
intgetWidth()

        return mWidth;
    
booleaninitialize(Surface surface)

        mInitialized = true;
        updateEnabledState(surface);
        boolean status = nInitialize(mNativeProxy, surface);
        surface.allocateBuffers();
        return status;
    
voidinvalidate(Surface surface)

        updateSurface(surface);
    
voidinvalidateRoot()

        mRootNodeNeedsUpdate = true;
    
static voidinvokeFunctor(long functor, boolean waitForCompletion)

        nInvokeFunctor(functor, waitForCompletion);
    
booleanloadSystemProperties()

        boolean changed = nLoadSystemProperties(mNativeProxy);
        boolean wantProfiling = checkIfProfilingRequested();
        if (wantProfiling != mProfilingEnabled) {
            mProfilingEnabled = wantProfiling;
            changed = true;
        }
        if (changed) {
            invalidateRoot();
        }
        return changed;
    
private static native voidnBuildLayer(long nativeProxy, long node)

private static native voidnCancelLayerUpdate(long nativeProxy, long layer)

private static native booleannCopyLayerInto(long nativeProxy, long layer, long bitmap)

private static native longnCreateProxy(boolean translucent, long rootRenderNode)

private static native longnCreateRootRenderNode()

private static native longnCreateTextureLayer(long nativeProxy)

private static native voidnDeleteProxy(long nativeProxy)

private static native voidnDestroy(long nativeProxy)

private static native voidnDestroyHardwareResources(long nativeProxy)

private static native voidnDetachSurfaceTexture(long nativeProxy, long layer)

private static native voidnDumpProfileInfo(long nativeProxy, java.io.FileDescriptor fd)

private static native voidnFence(long nativeProxy)

private static native booleannInitialize(long nativeProxy, Surface window)

private static native voidnInvokeFunctor(long functor, boolean waitForCompletion)

private static native booleannLoadSystemProperties(long nativeProxy)

private static native voidnNotifyFramePending(long nativeProxy)

private static native booleannPauseSurface(long nativeProxy, Surface window)

private static native voidnPushLayerUpdate(long nativeProxy, long layer)

private static native voidnRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode)

private static native voidnSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map)

private static native voidnSetFrameInterval(long nativeProxy, long frameIntervalNanos)

private static native voidnSetOpaque(long nativeProxy, boolean opaque)

private static native voidnSetup(long nativeProxy, int width, int height, float lightX, float lightY, float lightZ, float lightRadius, int ambientShadowAlpha, int spotShadowAlpha)

private static native voidnStopDrawing(long nativeProxy)

private static native intnSyncAndDrawFrame(long nativeProxy, long frameTimeNanos, long recordDuration, float density)

private static native voidnTrimMemory(int level)

private static native voidnUpdateSurface(long nativeProxy, Surface window)

public voidnotifyFramePending()

        nNotifyFramePending(mNativeProxy);
    
voidonLayerDestroyed(HardwareLayer layer)

        nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
    
booleanpauseSurface(Surface surface)

        return nPauseSurface(mNativeProxy, surface);
    
voidpushLayerUpdate(HardwareLayer layer)

        nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
    
voidregisterAnimatingRenderNode(RenderNode animator)

        nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
    
private static intsearch(java.lang.String[] values, java.lang.String value)

        for (int i = 0; i < values.length; i++) {
            if (values[i].equals(value)) return i;
        }
        return -1;
    
voidsetName(java.lang.String name)

    
voidsetOpaque(boolean opaque)

        nSetOpaque(mNativeProxy, opaque && !mHasInsets);
    
voidsetup(int width, int height, android.graphics.Rect surfaceInsets)

        final float lightX = width / 2.0f;
        mWidth = width;
        mHeight = height;
        if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0
                || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) {
            mHasInsets = true;
            mInsetLeft = surfaceInsets.left;
            mInsetTop = surfaceInsets.top;
            mSurfaceWidth = width + mInsetLeft + surfaceInsets.right;
            mSurfaceHeight = height + mInsetTop + surfaceInsets.bottom;

            // If the surface has insets, it can't be opaque.
            setOpaque(false);
        } else {
            mHasInsets = false;
            mInsetLeft = 0;
            mInsetTop = 0;
            mSurfaceWidth = width;
            mSurfaceHeight = height;
        }
        mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
        nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight,
                lightX, mLightY, mLightZ, mLightRadius,
                mAmbientShadowAlpha, mSpotShadowAlpha);
    
static native voidsetupShadersDiskCache(java.lang.String cacheFile)

voidstopDrawing()

        nStopDrawing(mNativeProxy);
    
static voidtrimMemory(int level)

        nTrimMemory(level);
    
private voidupdateEnabledState(Surface surface)

        if (surface == null || !surface.isValid()) {
            setEnabled(false);
        } else {
            setEnabled(mInitialized);
        }
    
private voidupdateRootDisplayList(View view, HardwareDrawCallbacks callbacks)

        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
        updateViewTreeDisplayList(view);

        if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
            HardwareCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
            try {
                final int saveCount = canvas.save();
                canvas.translate(mInsetLeft, mInsetTop);
                callbacks.onHardwarePreDraw(canvas);

                canvas.insertReorderBarrier();
                canvas.drawRenderNode(view.getDisplayList());
                canvas.insertInorderBarrier();

                callbacks.onHardwarePostDraw(canvas);
                canvas.restoreToCount(saveCount);
                mRootNodeNeedsUpdate = false;
            } finally {
                mRootNode.end(canvas);
            }
        }
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    
voidupdateSurface(Surface surface)

        updateEnabledState(surface);
        nUpdateSurface(mNativeProxy, surface);
    
private voidupdateViewTreeDisplayList(View view)

        view.mPrivateFlags |= View.PFLAG_DRAWN;
        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
                == View.PFLAG_INVALIDATED;
        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
        view.getDisplayList();
        view.mRecreateDisplayList = false;