diff options
author | John Reck <jreck@google.com> | 2018-10-29 16:45:58 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2018-11-08 15:32:35 -0800 |
commit | 8785ceb3b94b78312cd24e22f05610d9b654221e (patch) | |
tree | b5d3016cfa322fb354bf41b09ca86abc8e10365a | |
parent | 22b63148b14a0aac39323c1590c1cae3dc101979 (diff) |
Refactors and a potential public API for rendering
Split out the View/ViewRootImpl bits from the
hardware rendering bits.
Create a potential public API surface for
hardware rendering
Bug: 112709971
Test: builds & boots
Change-Id: I9e6f44b07a170574a905f42338282c4bb7e95f56
-rw-r--r-- | config/preloaded-classes | 2 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 8 | ||||
-rw-r--r-- | core/java/android/view/Choreographer.java | 1 | ||||
-rw-r--r-- | core/java/android/view/FrameMetricsObserver.java | 5 | ||||
-rw-r--r-- | core/java/android/view/TextureLayer.java | 8 | ||||
-rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 659 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 7 | ||||
-rw-r--r-- | core/jni/android_view_Surface.cpp | 8 | ||||
-rw-r--r-- | core/jni/android_view_ThreadedRenderer.cpp | 66 | ||||
-rw-r--r-- | graphics/java/android/graphics/FrameInfo.java (renamed from core/java/android/view/FrameInfo.java) | 48 | ||||
-rw-r--r-- | graphics/java/android/graphics/HardwareRenderer.java | 1030 | ||||
-rw-r--r-- | libs/hwui/FrameInfoVisualizer.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 12 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 5 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 22 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 11 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderThread.h | 2 | ||||
-rw-r--r-- | libs/hwui/tests/macrobench/TestSceneRunner.cpp | 6 |
18 files changed, 1186 insertions, 715 deletions
diff --git a/config/preloaded-classes b/config/preloaded-classes index b6bff9c78544..22fc5e80787f 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -3240,7 +3240,7 @@ android.view.FocusFinder$1 android.view.FocusFinder$FocusSorter android.view.FocusFinder$UserSpecifiedFocusComparator android.view.FocusFinder$UserSpecifiedFocusComparator$NextFocusGetter -android.view.FrameInfo +android.graphics.FrameInfo android.view.FrameMetrics android.view.FrameMetricsObserver android.view.FrameStats diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9079f1a174a2..805fb6829129 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -72,6 +72,7 @@ import android.database.sqlite.SQLiteDebug; import android.database.sqlite.SQLiteDebug.DbStats; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.HardwareRenderer; import android.graphics.ImageDecoder; import android.hardware.display.DisplayManagerGlobal; import android.net.ConnectivityManager; @@ -5652,7 +5653,7 @@ public final class ActivityThread extends ClientTransactionHandler { int uid = Process.myUid(); String[] packages = getPackageManager().getPackagesForUid(uid); if (packages != null) { - ThreadedRenderer.setupDiskCache(codeCacheDir); + HardwareRenderer.setupDiskCache(codeCacheDir); RenderScriptCacheDir.setupDiskCache(codeCacheDir); } } catch (RemoteException e) { @@ -5887,7 +5888,8 @@ public final class ActivityThread extends ClientTransactionHandler { // Allow renderer debugging features if we're debuggable. boolean isAppDebuggable = (data.appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; - ThreadedRenderer.setDebuggingEnabled(isAppDebuggable || Build.IS_DEBUGGABLE); + HardwareRenderer.setDebuggingEnabled(isAppDebuggable || Build.IS_DEBUGGABLE); + HardwareRenderer.setPackageName(data.appInfo.packageName); /** * Initialize the default http proxy in this process for the reasons we set the time zone. @@ -5954,7 +5956,7 @@ public final class ActivityThread extends ClientTransactionHandler { StrictMode.setThreadPolicyMask(oldMask); } } else { - ThreadedRenderer.setIsolatedProcess(true); + HardwareRenderer.setIsolatedProcess(true); } // If we use profiles, setup the dex reporter to notify package manager diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index a8727760095b..96ef8ba1a241 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -21,6 +21,7 @@ import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; +import android.graphics.FrameInfo; import android.hardware.display.DisplayManagerGlobal; import android.os.Build; import android.os.Handler; diff --git a/core/java/android/view/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java index 597089b98e1a..0f38e847f4bd 100644 --- a/core/java/android/view/FrameMetricsObserver.java +++ b/core/java/android/view/FrameMetricsObserver.java @@ -40,8 +40,9 @@ public class FrameMetricsObserver { @UnsupportedAppUsage private FrameMetrics mFrameMetrics; - /* package */ Window.OnFrameMetricsAvailableListener mListener; - /* package */ VirtualRefBasePtr mNative; + /* pacage */ Window.OnFrameMetricsAvailableListener mListener; + /** @hide */ + public VirtualRefBasePtr mNative; /** * Creates a FrameMetricsObserver diff --git a/core/java/android/view/TextureLayer.java b/core/java/android/view/TextureLayer.java index d89d634c6a25..46dd436e27a5 100644 --- a/core/java/android/view/TextureLayer.java +++ b/core/java/android/view/TextureLayer.java @@ -18,6 +18,7 @@ package android.view; import android.annotation.Nullable; import android.graphics.Bitmap; +import android.graphics.HardwareRenderer; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.SurfaceTexture; @@ -32,10 +33,10 @@ import com.android.internal.util.VirtualRefBasePtr; * @hide */ public final class TextureLayer { - private ThreadedRenderer mRenderer; + private HardwareRenderer mRenderer; private VirtualRefBasePtr mFinalizer; - private TextureLayer(ThreadedRenderer renderer, long deferredUpdater) { + private TextureLayer(HardwareRenderer renderer, long deferredUpdater) { if (renderer == null || deferredUpdater == 0) { throw new IllegalArgumentException("Either hardware renderer: " + renderer + " or deferredUpdater: " + deferredUpdater + " is invalid"); @@ -139,7 +140,8 @@ public final class TextureLayer { mRenderer.pushLayerUpdate(this); } - static TextureLayer adoptTextureLayer(ThreadedRenderer renderer, long layer) { + /** @hide */ + public static TextureLayer adoptTextureLayer(HardwareRenderer renderer, long layer) { return new TextureLayer(renderer, layer); } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index f0f4c1c595b8..bac0154cc392 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -16,36 +16,24 @@ package android.view; -import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; -import android.app.ActivityManager; import android.content.Context; import android.content.res.TypedArray; -import android.graphics.Bitmap; +import android.graphics.HardwareRenderer; import android.graphics.Point; import android.graphics.RecordingCanvas; import android.graphics.Rect; import android.graphics.RenderNode; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemProperties; import android.os.Trace; -import android.util.Log; import android.view.Surface.OutOfResourcesException; import android.view.View.AttachInfo; import android.view.animation.AnimationUtils; import com.android.internal.R; -import com.android.internal.util.VirtualRefBasePtr; -import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; /** * Threaded renderer that proxies the rendering to a render thread. Most calls @@ -66,15 +54,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ -public final class ThreadedRenderer { - private static final String LOG_TAG = "ThreadedRenderer"; - - /** - * Name of the file that holds the shaders cache. - */ - private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache"; - private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache"; - +public final class ThreadedRenderer extends HardwareRenderer { /** * System property used to enable or disable threaded rendering profiling. * The default value of this property is assumed to be false. @@ -271,21 +251,6 @@ public final class ThreadedRenderer { } /** - * Sets the directory to use as a persistent storage for threaded rendering - * resources. - * - * @param cacheDir A directory the current process can write to - * - * @hide - */ - @UnsupportedAppUsage - public static void setupDiskCache(File cacheDir) { - ThreadedRenderer.setupShadersDiskCache( - new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(), - new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath()); - } - - /** * Creates a threaded renderer using OpenGL. * * @param translucent True if the surface is translucent, false otherwise @@ -300,55 +265,10 @@ public final class ThreadedRenderer { return renderer; } - /** - * Invoke this method when the system is running out of memory. This - * method will attempt to recover as much memory as possible, based on - * the specified hint. - * - * @param level Hint about the amount of memory that should be trimmed, - * see {@link android.content.ComponentCallbacks} - */ - public static void trimMemory(int level) { - nTrimMemory(level); - } - - public static void overrideProperty(@NonNull String name, @NonNull String value) { - if (name == null || value == null) { - throw new IllegalArgumentException("name and value must be non-null"); - } - nOverrideProperty(name, value); - } - - // Keep in sync with DrawFrameTask.h SYNC_* flags - // Nothing interesting to report - private static final int SYNC_OK = 0; - // Needs a ViewRoot invalidate - private static final int SYNC_INVALIDATE_REQUIRED = 1 << 0; - // Spoiler: the reward is GPU-accelerated drawing, better find that Surface! - private static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1; - // setStopped is true, drawing is false - // TODO: Remove this and SYNC_LOST_SURFACE_REWARD_IF_FOUND? - // This flag isn't really used as there's nothing that we care to do - // in response, so it really just exists to differentiate from LOST_SURFACE - // but possibly both can just be deleted. - private static final int SYNC_CONTEXT_IS_STOPPED = 1 << 2; - private static final int SYNC_FRAME_DROPPED = 1 << 3; - private static final String[] VISUALIZERS = { PROFILE_PROPERTY_VISUALIZE_BARS, }; - private static final int FLAG_DUMP_FRAMESTATS = 1 << 0; - private static final int FLAG_DUMP_RESET = 1 << 1; - private static final int FLAG_DUMP_ALL = FLAG_DUMP_FRAMESTATS; - - @IntDef(flag = true, prefix = { "FLAG_DUMP_" }, value = { - FLAG_DUMP_FRAMESTATS, - FLAG_DUMP_RESET - }) - @Retention(RetentionPolicy.SOURCE) - public @interface DumpFlags {} - // Size of the rendered content. private int mWidth, mHeight; @@ -362,51 +282,37 @@ public final class ThreadedRenderer { // Whether the surface has insets. Used to protect opacity. private boolean mHasInsets; - // Light and shadow properties specified by the theme. + // Light properties specified by the theme. 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 = false; - private RenderNode mRootNode; private boolean mRootNodeNeedsUpdate; private boolean mEnabled; private boolean mRequested = true; - private boolean mIsOpaque = false; ThreadedRenderer(Context context, boolean translucent, String name) { + super(); + setName(name); + setOpaque(!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); + float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0); + float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0); a.recycle(); - - long rootNodePtr = nCreateRootRenderNode(); - mRootNode = RenderNode.adopt(rootNodePtr); - mRootNode.setClipToBounds(false); - mIsOpaque = !translucent; - mNativeProxy = nCreateProxy(translucent, rootNodePtr); - nSetName(mNativeProxy, name); - - ProcessInitializer.sInstance.init(context, mNativeProxy); - - loadSystemProperties(); + setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha); } - /** - * Destroys the threaded rendering context. - */ - void destroy() { + @Override + public void destroy() { mInitialized = false; updateEnabledState(null); - nDestroy(mNativeProxy, mRootNode.mNativeRenderNode); + super.destroy(); } /** @@ -464,7 +370,7 @@ public final class ThreadedRenderer { boolean status = !mInitialized; mInitialized = true; updateEnabledState(surface); - nInitialize(mNativeProxy, surface); + setSurface(surface); return status; } @@ -505,26 +411,18 @@ public final class ThreadedRenderer { */ void updateSurface(Surface surface) throws OutOfResourcesException { updateEnabledState(surface); - nUpdateSurface(mNativeProxy, surface); - } - - /** - * Halts any current rendering into the surface. Use this if it is unclear whether - * or not the surface used by the ThreadedRenderer will be changing. It - * Suspends any rendering into the surface, but will not do any destruction. - * - * Any subsequent draws will override the pause, resuming normal operation. - */ - boolean pauseSurface(Surface surface) { - return nPauseSurface(mNativeProxy, surface); + setSurface(surface); } - /** - * Hard stops or resumes rendering into the surface. This flag is used to - * determine whether or not it is safe to use the given surface *at all* - */ - void setStopped(boolean stopped) { - nSetStopped(mNativeProxy, stopped); + @Override + public void setSurface(Surface surface) { + // TODO: Do we ever pass a non-null but isValid() = false surface? + // This is here to be super conservative for ViewRootImpl + if (surface != null && surface.isValid()) { + super.setSurface(surface); + } else { + super.setSurface(null); + } } /** @@ -535,7 +433,7 @@ public final class ThreadedRenderer { */ void destroyHardwareResources(View view) { destroyResources(view); - nDestroyHardwareResources(mNativeProxy); + destroyHardwareResources(); } private static void destroyResources(View view) { @@ -543,14 +441,6 @@ public final class ThreadedRenderer { } /** - * Detaches the layer's surface texture from the GL context and releases - * the texture id - */ - void detachSurfaceTexture(long hardwareLayer) { - nDetachSurfaceTexture(mNativeProxy, hardwareLayer); - } - - /** * Sets up the renderer for drawing. * * @param width The width of the drawing surface. @@ -581,8 +471,6 @@ public final class ThreadedRenderer { } mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight); - nSetup(mNativeProxy, mLightRadius, - mAmbientShadowAlpha, mSpotShadowAlpha); setLightCenter(attachInfo); } @@ -598,27 +486,7 @@ public final class ThreadedRenderer { attachInfo.mDisplay.getRealSize(displaySize); final float lightX = displaySize.x / 2f - attachInfo.mWindowLeft; final float lightY = mLightY - attachInfo.mWindowTop; - - nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ); - } - - /** - * Change the ThreadedRenderer's opacity - */ - void setOpaque(boolean opaque) { - mIsOpaque = opaque && !mHasInsets; - nSetOpaque(mNativeProxy, mIsOpaque); - } - - boolean isOpaque() { - return mIsOpaque; - } - - /** - * Enable/disable wide gamut rendering on this renderer. - */ - void setWideGamut(boolean wideGamut) { - nSetWideGamut(mNativeProxy, wideGamut); + setLightSourceGeometry(lightX, lightY, mLightZ, mLightRadius); } /** @@ -663,18 +531,12 @@ public final class ThreadedRenderer { break; } } - nDumpProfileInfo(mNativeProxy, fd, flags); + dumpProfileInfo(fd, flags); } - /** - * Loads system properties used by the renderer. This method is invoked - * whenever system properties are modified. Implementations can use this - * to trigger live updates of the renderer based on properties. - * - * @return True if a property has changed. - */ - boolean loadSystemProperties() { - boolean changed = nLoadSystemProperties(mNativeProxy); + @Override + public boolean loadSystemProperties() { + boolean changed = super.loadSystemProperties(); if (changed) { invalidateRoot(); } @@ -695,72 +557,27 @@ public final class ThreadedRenderer { updateViewTreeDisplayList(view); if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) { - RecordingCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight); + RecordingCanvas canvas = mRootNode.startRecording(mSurfaceWidth, mSurfaceHeight); try { final int saveCount = canvas.save(); canvas.translate(mInsetLeft, mInsetTop); callbacks.onPreDraw(canvas); - canvas.insertReorderBarrier(); + canvas.enableZ(); canvas.drawRenderNode(view.updateDisplayListIfDirty()); - canvas.insertInorderBarrier(); + canvas.disableZ(); callbacks.onPostDraw(canvas); canvas.restoreToCount(saveCount); mRootNodeNeedsUpdate = false; } finally { - mRootNode.end(canvas); + mRootNode.endRecording(); } } Trace.traceEnd(Trace.TRACE_TAG_VIEW); } /** - * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the - * rendernode of the UI thread. - * @param node The node to add. - * @param placeFront If true, the render node will be placed in front of the content node, - * otherwise behind the content node. - */ - @UnsupportedAppUsage - public void addRenderNode(RenderNode node, boolean placeFront) { - nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront); - } - - /** - * Only especially added render nodes can be removed. - * @param node The node which was added via addRenderNode which should get removed again. - */ - @UnsupportedAppUsage - public void removeRenderNode(RenderNode node) { - nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode); - } - - /** - * Draws a particular render node. If the node is not the content node, only the additional - * nodes will get drawn and the content remains untouched. - * @param node The node to be drawn. - */ - @UnsupportedAppUsage - public void drawRenderNode(RenderNode node) { - nDrawRenderNode(mNativeProxy, node.mNativeRenderNode); - } - - /** - * To avoid unnecessary overdrawing of the main content all additionally passed render nodes - * will be prevented to overdraw this area. It will be synchronized with the draw call. - * This should be updated in the content view's draw call. - * @param left The left side of the protected bounds. - * @param top The top side of the protected bounds. - * @param right The right side of the protected bounds. - * @param bottom The bottom side of the protected bounds. - */ - @UnsupportedAppUsage - public void setContentDrawBounds(int left, int top, int right, int bottom) { - nSetContentDrawBounds(mNativeProxy, left, top, right, bottom); - } - - /** * Interface used to receive callbacks whenever a view is drawn by * a threaded renderer instance. */ @@ -819,11 +636,10 @@ public final class ThreadedRenderer { attachInfo.mPendingAnimatingRenderNodes = null; } - final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo; if (frameDrawingCallback != null) { - nSetFrameCallback(mNativeProxy, frameDrawingCallback); + setFrameCallback(frameDrawingCallback); } - int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length); + int syncResult = syncAndDrawFrame(choreographer.mFrameInfo); if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) { setEnabled(false); attachInfo.mViewRootImpl.mSurface.release(); @@ -831,207 +647,40 @@ public final class ThreadedRenderer { // if it is still needed or do nothing if we are no longer drawing attachInfo.mViewRootImpl.invalidate(); } - if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) { + if ((syncResult & SYNC_REDRAW_REQUESTED) != 0) { attachInfo.mViewRootImpl.invalidate(); } } - void setFrameCompleteCallback(FrameCompleteCallback callback) { - nSetFrameCompleteCallback(mNativeProxy, callback); - } - - static void invokeFunctor(long functor, boolean waitForCompletion) { - nInvokeFunctor(functor, waitForCompletion); - } - - /** - * Creates a new hardware layer. A hardware layer built by calling this - * method will be treated as a texture layer, instead of as a render target. - * - * @return A hardware layer - */ - TextureLayer createTextureLayer() { - long layer = nCreateTextureLayer(mNativeProxy); - return TextureLayer.adoptTextureLayer(this, layer); - } - - - void buildLayer(RenderNode node) { - if (node.hasDisplayList()) { - nBuildLayer(mNativeProxy, node.mNativeRenderNode); - } - } - - - boolean copyLayerInto(final TextureLayer layer, final Bitmap bitmap) { - return nCopyLayerInto(mNativeProxy, - layer.getDeferredLayerUpdater(), bitmap); - } - - /** - * Indicates that the specified hardware layer needs to be updated - * as soon as possible. - * - * @param layer The hardware layer that needs an update - */ - void pushLayerUpdate(TextureLayer layer) { - nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); - } - - /** - * Tells the HardwareRenderer that the layer is destroyed. The renderer - * should remove the layer from any update queues. - */ - void onLayerDestroyed(TextureLayer layer) { - nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); - } - - /** - * Blocks until all previously queued work has completed. - */ - void fence() { - nFence(mNativeProxy); - } - - /** - * Prevents any further drawing until draw() is called. This is a signal - * that the contents of the RenderNode tree are no longer safe to play back. - * In practice this usually means that there are Functor pointers in the - * display list that are no longer valid. - */ - void stopDrawing() { - nStopDrawing(mNativeProxy); - } - - /** - * Called by {@link ViewRootImpl} when a new performTraverals is scheduled. - */ - public void notifyFramePending() { - nNotifyFramePending(mNativeProxy); - } - - - void registerAnimatingRenderNode(RenderNode animator) { - nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode); - } - - void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) { - nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode, - animator.getAnimatorNativePtr()); - } - - public static int copySurfaceInto(Surface surface, Rect srcRect, Bitmap bitmap) { - if (srcRect == null) { - // Empty rect means entire surface - return nCopySurfaceInto(surface, 0, 0, 0, 0, bitmap); - } else { - return nCopySurfaceInto(surface, srcRect.left, srcRect.top, - srcRect.right, srcRect.bottom, bitmap); - } - } - - /** - * Creates a {@link android.graphics.Bitmap.Config#HARDWARE} bitmap from the given - * RenderNode. Note that the RenderNode should be created as a root node (so x/y of 0,0), and - * not the RenderNode from a View. - **/ - @UnsupportedAppUsage - public static Bitmap createHardwareBitmap(RenderNode node, int width, int height) { - return nCreateHardwareBitmap(node.mNativeRenderNode, width, height); - } - - /** - * Sets whether or not high contrast text rendering is enabled. The setting is global - * but only affects content rendered after the change is made. - */ - public static void setHighContrastText(boolean highContrastText) { - nSetHighContrastText(highContrastText); - } - - /** - * If set RenderThread will avoid doing any IPC using instead a fake vsync & DisplayInfo source - */ - public static void setIsolatedProcess(boolean isIsolated) { - nSetIsolatedProcess(isIsolated); - } - - /** - * If set extra graphics debugging abilities will be enabled such as dumping skp - */ - public static void setDebuggingEnabled(boolean enable) { - nSetDebuggingEnabled(enable); - } - - void allocateBuffers(Surface surface) { - nAllocateBuffers(mNativeProxy, surface); - } - - @Override - protected void finalize() throws Throwable { - try { - nDeleteProxy(mNativeProxy); - mNativeProxy = 0; - } finally { - super.finalize(); - } - } - /** The root of everything */ public @NonNull RenderNode getRootNode() { return mRootNode; } - private boolean mForceDark = false; - - /** - * Whether or not the force-dark feature should be used for this renderer. - */ - public boolean setForceDark(boolean enable) { - if (mForceDark != enable) { - mForceDark = enable; - nSetForceDark(mNativeProxy, enable); - return true; - } - return false; - } - /** * Basic synchronous renderer. Currently only used to render the Magnifier, so use with care. * TODO: deduplicate against ThreadedRenderer. * * @hide */ - public static class SimpleRenderer { - private final RenderNode mRootNode; - private long mNativeProxy; - private final float mLightY, mLightZ; - private Surface mSurface; - private final FrameInfo mFrameInfo = new FrameInfo(); + public static class SimpleRenderer extends HardwareRenderer { + private final float mLightY, mLightZ, mLightRadius; public SimpleRenderer(final Context context, final String name, final Surface surface) { + super(); + setName(name); + setOpaque(false); + setSurface(surface); 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); - final float lightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0); + mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0); final int ambientShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f); final int spotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f); a.recycle(); - - final long rootNodePtr = nCreateRootRenderNode(); - mRootNode = RenderNode.adopt(rootNodePtr); - mRootNode.setClipToBounds(false); - mNativeProxy = nCreateProxy(true /* translucent */, rootNodePtr); - nSetName(mNativeProxy, name); - - ProcessInitializer.sInstance.init(context, mNativeProxy); - nLoadSystemProperties(mNativeProxy); - - nSetup(mNativeProxy, lightRadius, ambientShadowAlpha, spotShadowAlpha); - - mSurface = surface; - nUpdateSurface(mNativeProxy, surface); + setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha); } /** @@ -1045,7 +694,7 @@ public final class ThreadedRenderer { final float lightX = displaySize.x / 2f - windowLeft; final float lightY = mLightY - windowTop; - nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ); + setLightSourceGeometry(lightX, lightY, mLightZ, mLightRadius); } public RenderNode getRootNode() { @@ -1057,222 +706,10 @@ public final class ThreadedRenderer { */ public void draw(final FrameDrawingCallback callback) { final long vsync = AnimationUtils.currentAnimationTimeMillis() * 1000000L; - mFrameInfo.setVsync(vsync, vsync); - mFrameInfo.addFlags(1 << 2 /* VSYNC */); if (callback != null) { - nSetFrameCallback(mNativeProxy, callback); + setFrameCallback(callback); } - nSyncAndDrawFrame(mNativeProxy, mFrameInfo.mFrameInfo, mFrameInfo.mFrameInfo.length); + syncAndDrawFrame(vsync); } - - /** - * Destroy the renderer. - */ - public void destroy() { - mSurface = null; - nDestroy(mNativeProxy, mRootNode.mNativeRenderNode); - } - - @Override - protected void finalize() throws Throwable { - try { - nDeleteProxy(mNativeProxy); - mNativeProxy = 0; - } finally { - super.finalize(); - } - } - } - - /** - * Interface used to receive callbacks when a frame is being drawn. - */ - public interface FrameDrawingCallback { - /** - * Invoked during a frame drawing. - * - * @param frame The id of the frame being drawn. - */ - void onFrameDraw(long frame); } - - /** - * Interface used to be notified when a frame has finished rendering - */ - public interface FrameCompleteCallback { - /** - * Invoked after a frame draw - * - * @param frameNr The id of the frame that was drawn. - */ - void onFrameComplete(long frameNr); - } - - private static class ProcessInitializer { - static ProcessInitializer sInstance = new ProcessInitializer(); - - private boolean mInitialized = false; - - private Context mAppContext; - private IGraphicsStats mGraphicsStatsService; - private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() { - @Override - public void onRotateGraphicsStatsBuffer() throws RemoteException { - rotateBuffer(); - } - }; - - private ProcessInitializer() {} - - synchronized void init(Context context, long renderProxy) { - if (mInitialized) return; - mInitialized = true; - mAppContext = context.getApplicationContext(); - - initSched(renderProxy); - - if (mAppContext != null) { - initGraphicsStats(); - } - } - - private void initSched(long renderProxy) { - try { - int tid = nGetRenderThreadTid(renderProxy); - ActivityManager.getService().setRenderThread(tid); - } catch (Throwable t) { - Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t); - } - } - - private void initGraphicsStats() { - try { - IBinder binder = ServiceManager.getService("graphicsstats"); - if (binder == null) return; - mGraphicsStatsService = IGraphicsStats.Stub.asInterface(binder); - requestBuffer(); - } catch (Throwable t) { - Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t); - } - } - - private void rotateBuffer() { - nRotateProcessStatsBuffer(); - requestBuffer(); - } - - private void requestBuffer() { - try { - final String pkg = mAppContext.getApplicationInfo().packageName; - ParcelFileDescriptor pfd = mGraphicsStatsService - .requestBufferForProcess(pkg, mGraphicsStatsCallback); - nSetProcessStatsBuffer(pfd.getFd()); - pfd.close(); - } catch (Throwable t) { - Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t); - } - } - } - - void addFrameMetricsObserver(FrameMetricsObserver observer) { - long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer); - observer.mNative = new VirtualRefBasePtr(nativeObserver); - } - - void removeFrameMetricsObserver(FrameMetricsObserver observer) { - nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get()); - observer.mNative = null; - } - - /** b/68769804: For low FPS experiments. */ - public static void setFPSDivisor(int divisor) { - nHackySetRTAnimationsEnabled(divisor <= 1); - } - - /** - * Changes the OpenGL context priority if IMG_context_priority extension is available. Must be - * called before any OpenGL context is created. - * - * @param priority The priority to use. Must be one of EGL_CONTEXT_PRIORITY_* values. - */ - public static void setContextPriority(int priority) { - nSetContextPriority(priority); - } - - /** Not actually public - internal use only. This doc to make lint happy */ - public static native void disableVsync(); - - static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile); - - private static native void nRotateProcessStatsBuffer(); - private static native void nSetProcessStatsBuffer(int fd); - private static native int nGetRenderThreadTid(long nativeProxy); - - private static native long nCreateRootRenderNode(); - private static native long nCreateProxy(boolean translucent, long rootRenderNode); - private static native void nDeleteProxy(long nativeProxy); - - private static native boolean nLoadSystemProperties(long nativeProxy); - private static native void nSetName(long nativeProxy, String name); - - private static native void nInitialize(long nativeProxy, Surface window); - private static native void nUpdateSurface(long nativeProxy, Surface window); - private static native boolean nPauseSurface(long nativeProxy, Surface window); - private static native void nSetStopped(long nativeProxy, boolean stopped); - private static native void nSetup(long nativeProxy, - float lightRadius, int ambientShadowAlpha, int spotShadowAlpha); - private static native void nSetLightCenter(long nativeProxy, - float lightX, float lightY, float lightZ); - private static native void nSetOpaque(long nativeProxy, boolean opaque); - private static native void nSetWideGamut(long nativeProxy, boolean wideGamut); - private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size); - private static native void nDestroy(long nativeProxy, long rootRenderNode); - private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode); - private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator); - - private static native void nInvokeFunctor(long functor, boolean waitForCompletion); - - private static native long nCreateTextureLayer(long nativeProxy); - private static native void nBuildLayer(long nativeProxy, long node); - private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap); - private static native void nPushLayerUpdate(long nativeProxy, long layer); - private static native void nCancelLayerUpdate(long nativeProxy, long layer); - private static native void nDetachSurfaceTexture(long nativeProxy, long layer); - - private static native void nDestroyHardwareResources(long nativeProxy); - private static native void nTrimMemory(int level); - private static native void nOverrideProperty(String name, String value); - - private static native void nFence(long nativeProxy); - private static native void nStopDrawing(long nativeProxy); - private static native void nNotifyFramePending(long nativeProxy); - - private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd, - @DumpFlags int dumpFlags); - - private static native void nAddRenderNode(long nativeProxy, long rootRenderNode, - boolean placeFront); - private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode); - private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode); - private static native void nSetContentDrawBounds(long nativeProxy, int left, - int top, int right, int bottom); - private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback); - private static native void nSetFrameCompleteCallback(long nativeProxy, - FrameCompleteCallback callback); - - private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer); - private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver); - - private static native int nCopySurfaceInto(Surface surface, - int srcLeft, int srcTop, int srcRight, int srcBottom, Bitmap bitmap); - - private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height); - private static native void nSetHighContrastText(boolean enabled); - // For temporary experimentation b/66945974 - private static native void nHackySetRTAnimationsEnabled(boolean enabled); - private static native void nSetDebuggingEnabled(boolean enabled); - private static native void nSetIsolatedProcess(boolean enabled); - private static native void nSetContextPriority(int priority); - private static native void nAllocateBuffers(long nativeProxy, Surface window); - private static native void nSetForceDark(long nativeProxy, boolean enabled); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index dd1f6407682f..a23d68b17245 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -46,6 +46,8 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.FrameInfo; +import android.graphics.HardwareRenderer.FrameDrawingCallback; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Point; @@ -84,7 +86,6 @@ import android.util.TimeUtils; import android.util.TypedValue; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl.Transaction; -import android.view.ThreadedRenderer.FrameDrawingCallback; import android.view.View.AttachInfo; import android.view.View.FocusDirection; import android.view.View.MeasureSpec; @@ -2148,7 +2149,7 @@ public final class ViewRootImpl implements ViewParent, // relayoutWindow may decide to destroy mSurface. As that decision // happens in WindowManager service, we need to be defensive here // and stop using the surface in case it gets destroyed. - if (mAttachInfo.mThreadedRenderer.pauseSurface(mSurface)) { + if (mAttachInfo.mThreadedRenderer.pause()) { // Animations were running so we need to push a frame // to resume them mDirty.set(0, 0, mWidth, mHeight); @@ -2266,7 +2267,7 @@ public final class ViewRootImpl implements ViewParent, & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) { // Don't pre-allocate if transparent regions // are requested as they may not be needed - mAttachInfo.mThreadedRenderer.allocateBuffers(mSurface); + mAttachInfo.mThreadedRenderer.allocateBuffers(); } } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index f512ce418a93..b8139a712fd7 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -556,18 +556,18 @@ static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfaceP proxy->setWideGamut(true); } proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer); - proxy->initialize(surface); + proxy->setSurface(surface); // Shadows can't be used via this interface, so just set the light source // to all 0s. - proxy->setup(0, 0, 0); - proxy->setLightCenter((Vector3){0, 0, 0}); + proxy->setLightAlpha(0, 0); + proxy->setLightGeometry((Vector3){0, 0, 0}, 0); return (jlong) proxy; } static void setSurface(JNIEnv* env, jclass clazz, jlong rendererPtr, jlong surfacePtr) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr); sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr)); - proxy->updateSurface(surface); + proxy->setSurface(surface); } static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) { diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 7a5b60493dcd..702741eb813c 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -686,31 +686,20 @@ static void android_view_ThreadedRenderer_setName(JNIEnv* env, jobject clazz, env->ReleaseStringUTFChars(jname, name); } -static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz, - jlong proxyPtr, jobject jsurface) { - RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - sp<Surface> surface = android_view_Surface_getSurface(env, jsurface); - proxy->initialize(surface); -} - -static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz, +static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz, jlong proxyPtr, jobject jsurface) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); sp<Surface> surface; if (jsurface) { surface = android_view_Surface_getSurface(env, jsurface); } - proxy->updateSurface(surface); + proxy->setSurface(surface); } -static jboolean android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz, - jlong proxyPtr, jobject jsurface) { +static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz, + jlong proxyPtr) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - sp<Surface> surface; - if (jsurface) { - surface = android_view_Surface_getSurface(env, jsurface); - } - return proxy->pauseSurface(surface); + return proxy->pause(); } static void android_view_ThreadedRenderer_setStopped(JNIEnv* env, jobject clazz, @@ -719,16 +708,16 @@ static void android_view_ThreadedRenderer_setStopped(JNIEnv* env, jobject clazz, proxy->setStopped(stopped); } -static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr, - jfloat lightRadius, jint ambientShadowAlpha, jint spotShadowAlpha) { +static void android_view_ThreadedRenderer_setLightAlpha(JNIEnv* env, jobject clazz, jlong proxyPtr, + jfloat ambientShadowAlpha, jfloat spotShadowAlpha) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - proxy->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha); + proxy->setLightAlpha((uint8_t) (255 * ambientShadowAlpha), (uint8_t) (255 * spotShadowAlpha)); } -static void android_view_ThreadedRenderer_setLightCenter(JNIEnv* env, jobject clazz, - jlong proxyPtr, jfloat lightX, jfloat lightY, jfloat lightZ) { +static void android_view_ThreadedRenderer_setLightGeometry(JNIEnv* env, jobject clazz, + jlong proxyPtr, jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - proxy->setLightCenter((Vector3){lightX, lightY, lightZ}); + proxy->setLightGeometry((Vector3){lightX, lightY, lightZ}, lightRadius); } static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz, @@ -990,13 +979,12 @@ static jobject android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode( { ContextFactory factory; RenderProxy proxy{true, renderNode, &factory}; - proxy.loadSystemProperties(); proxy.setSwapBehavior(SwapBehavior::kSwap_discardBuffer); - proxy.initialize(surface); + proxy.setSurface(surface); // Shadows can't be used via this interface, so just set the light source // to all 0s. - proxy.setup(0, 0, 0); - proxy.setLightCenter((Vector3){0, 0, 0}); + proxy.setLightAlpha(0, 0); + proxy.setLightGeometry((Vector3){0, 0, 0}, 0); nsecs_t vsync = systemTime(CLOCK_MONOTONIC); UiFrameInfoBuilder(proxy.frameInfo()) .setVsync(vsync, vsync) @@ -1058,10 +1046,9 @@ static void android_view_ThreadedRenderer_setContextPriority(JNIEnv*, jclass, } static void android_view_ThreadedRenderer_allocateBuffers(JNIEnv* env, jobject clazz, - jlong proxyPtr, jobject jsurface) { + jlong proxyPtr) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - sp<Surface> surface = android_view_Surface_getSurface(env, jsurface); - proxy->allocateBuffers(surface); + proxy->allocateBuffers(); } static void android_view_ThreadedRenderer_setForceDark(JNIEnv* env, jobject clazz, @@ -1118,7 +1105,7 @@ static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, job // JNI Glue // ---------------------------------------------------------------------------- -const char* const kClassPathName = "android/view/ThreadedRenderer"; +const char* const kClassPathName = "android/graphics/HardwareRenderer"; static const JNINativeMethod gMethods[] = { { "nRotateProcessStatsBuffer", "()V", (void*) android_view_ThreadedRenderer_rotateProcessStatsBuffer }, @@ -1129,12 +1116,11 @@ static const JNINativeMethod gMethods[] = { { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy }, { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties }, { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName }, - { "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize }, - { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface }, - { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface }, + { "nSetSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_setSurface }, + { "nPause", "(J)Z", (void*) android_view_ThreadedRenderer_pause }, { "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped }, - { "nSetup", "(JFII)V", (void*) android_view_ThreadedRenderer_setup }, - { "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter }, + { "nSetLightAlpha", "(JFF)V", (void*) android_view_ThreadedRenderer_setLightAlpha }, + { "nSetLightGeometry", "(JFFFF)V", (void*) android_view_ThreadedRenderer_setLightGeometry }, { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque }, { "nSetWideGamut", "(JZ)V", (void*) android_view_ThreadedRenderer_setWideGamut }, { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, @@ -1161,9 +1147,9 @@ static const JNINativeMethod gMethods[] = { { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode}, { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode}, { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds}, - { "nSetFrameCallback", "(JLandroid/view/ThreadedRenderer$FrameDrawingCallback;)V", + { "nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V", (void*)android_view_ThreadedRenderer_setFrameCallback}, - { "nSetFrameCompleteCallback", "(JLandroid/view/ThreadedRenderer$FrameCompleteCallback;)V", + { "nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V", (void*)android_view_ThreadedRenderer_setFrameCompleteCallback }, { "nAddFrameMetricsObserver", "(JLandroid/view/FrameMetricsObserver;)J", @@ -1182,7 +1168,7 @@ static const JNINativeMethod gMethods[] = { { "nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled }, { "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess }, { "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority }, - { "nAllocateBuffers", "(JLandroid/view/Surface;)V", (void*)android_view_ThreadedRenderer_allocateBuffers }, + { "nAllocateBuffers", "(J)V", (void*)android_view_ThreadedRenderer_allocateBuffers }, { "nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark }, }; @@ -1215,12 +1201,12 @@ int register_android_view_ThreadedRenderer(JNIEnv* env) { env, metricsClass, "mTimingData", "[J"); jclass frameCallbackClass = FindClassOrDie(env, - "android/view/ThreadedRenderer$FrameDrawingCallback"); + "android/graphics/HardwareRenderer$FrameDrawingCallback"); gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass, "onFrameDraw", "(J)V"); jclass frameCompleteClass = FindClassOrDie(env, - "android/view/ThreadedRenderer$FrameCompleteCallback"); + "android/graphics/HardwareRenderer$FrameCompleteCallback"); gFrameCompleteCallback.onFrameComplete = GetMethodIDOrDie(env, frameCompleteClass, "onFrameComplete", "(J)V"); diff --git a/core/java/android/view/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java index 6c5e048f05d2..42a5cc43eaa0 100644 --- a/core/java/android/view/FrameInfo.java +++ b/graphics/java/android/graphics/FrameInfo.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.view; +package android.graphics; import android.annotation.LongDef; @@ -33,14 +33,14 @@ import java.lang.annotation.RetentionPolicy; * long layout & measure took it's displayListRecordStart - performTraversalsStart. * * These constants must be kept in sync with FrameInfo.h in libhwui and are - * used for indexing into AttachInfo's mFrameInfo long[], which is intended + * used for indexing into AttachInfo's frameInfo long[], which is intended * to be quick to pass down to native via JNI, hence a pre-packed format * * @hide */ -final class FrameInfo { +public final class FrameInfo { - long[] mFrameInfo = new long[9]; + public long[] frameInfo = new long[9]; // Various flags set to provide extra metadata about the current frame private static final int FLAGS = 0; @@ -48,8 +48,11 @@ final class FrameInfo { // Is this the first-draw following a window layout? public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1; + // A renderer associated with just a Surface, not with a ViewRootImpl instance. + public static final long FLAG_SURFACE_CANVAS = 1 << 2; + @LongDef(flag = true, value = { - FLAG_WINDOW_LAYOUT_CHANGED }) + FLAG_WINDOW_LAYOUT_CHANGED, FLAG_SURFACE_CANVAS }) @Retention(RetentionPolicy.SOURCE) public @interface FrameInfoFlags {} @@ -78,41 +81,48 @@ final class FrameInfo { // When View:draw() started private static final int DRAW_START = 8; + /** checkstyle */ public void setVsync(long intendedVsync, long usedVsync) { - mFrameInfo[INTENDED_VSYNC] = intendedVsync; - mFrameInfo[VSYNC] = usedVsync; - mFrameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE; - mFrameInfo[NEWEST_INPUT_EVENT] = 0; - mFrameInfo[FLAGS] = 0; + frameInfo[INTENDED_VSYNC] = intendedVsync; + frameInfo[VSYNC] = usedVsync; + frameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE; + frameInfo[NEWEST_INPUT_EVENT] = 0; + frameInfo[FLAGS] = 0; } + /** checkstyle */ public void updateInputEventTime(long inputEventTime, long inputEventOldestTime) { - if (inputEventOldestTime < mFrameInfo[OLDEST_INPUT_EVENT]) { - mFrameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime; + if (inputEventOldestTime < frameInfo[OLDEST_INPUT_EVENT]) { + frameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime; } - if (inputEventTime > mFrameInfo[NEWEST_INPUT_EVENT]) { - mFrameInfo[NEWEST_INPUT_EVENT] = inputEventTime; + if (inputEventTime > frameInfo[NEWEST_INPUT_EVENT]) { + frameInfo[NEWEST_INPUT_EVENT] = inputEventTime; } } + /** checkstyle */ public void markInputHandlingStart() { - mFrameInfo[HANDLE_INPUT_START] = System.nanoTime(); + frameInfo[HANDLE_INPUT_START] = System.nanoTime(); } + /** checkstyle */ public void markAnimationsStart() { - mFrameInfo[ANIMATION_START] = System.nanoTime(); + frameInfo[ANIMATION_START] = System.nanoTime(); } + /** checkstyle */ public void markPerformTraversalsStart() { - mFrameInfo[PERFORM_TRAVERSALS_START] = System.nanoTime(); + frameInfo[PERFORM_TRAVERSALS_START] = System.nanoTime(); } + /** checkstyle */ public void markDrawStart() { - mFrameInfo[DRAW_START] = System.nanoTime(); + frameInfo[DRAW_START] = System.nanoTime(); } + /** checkstyle */ public void addFlags(@FrameInfoFlags long flags) { - mFrameInfo[FLAGS] |= flags; + frameInfo[FLAGS] |= flags; } } diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java new file mode 100644 index 000000000000..e4020554786b --- /dev/null +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -0,0 +1,1030 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics; + +import android.annotation.FloatRange; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.Activity; +import android.app.ActivityManager; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; +import android.view.FrameMetricsObserver; +import android.view.IGraphicsStats; +import android.view.IGraphicsStatsCallback; +import android.view.NativeVectorDrawableAnimator; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.TextureLayer; + +import com.android.internal.util.VirtualRefBasePtr; + +import java.io.File; +import java.io.FileDescriptor; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import sun.misc.Cleaner; + +/** + * <p>Creates an instance of a hardware-accelerated renderer. This is used to render a scene built + * from {@link RenderNode}'s to an output {@link android.view.Surface}. There can be as many + * HardwareRenderer instances as desired.</p> + * + * <h3>Threading</h3> + * <p>HardwareRenderer is not thread safe. An instance of a HardwareRenderer must only be + * created & used from a single thread. It does not matter what thread is used, however + * it must have a {@link android.os.Looper}. Multiple instances do not have to share the same + * thread, although they can.</p> + * + * <h3>Resources & lifecycle</h3> + * <p>All HardwareRenderer instances share a common render thread. The render thread contains + * the GPU context & resources necessary to do GPU-accelerated rendering. As such, the first + * HardwareRenderer created comes with the cost of also creating the associated GPU contexts, + * however each incremental HardwareRenderer thereafter is fairly cheap. The expected usage + * is to have a HardwareRenderer instance for every active {@link Surface}. For example + * when an Activity shows a Dialog the system internally will use 2 hardware renderers, both + * of which may be drawing at the same time.</p> + * <p>NOTE: Due to the shared, cooperative nature of the render thread it is critical that + * any {@link Surface} used must have a prompt, reliable consuming side. System-provided + * consumers such as {@link android.view.SurfaceView}, + * {@link android.view.Window#takeSurface(SurfaceHolder.Callback2)}, + * or {@link android.view.TextureView} all fit this requirement. However if custom consumers + * are used such as when using {@link SurfaceTexture} or {@link android.media.ImageReader} + * it is the app's responsibility to ensure that they consume updates promptly and rapidly. + * Failure to do so will cause the render thread to stall on that surface, blocking all + * HardwareRenderer instances.</p> + * + * @hide + */ +public class HardwareRenderer { + private static final String LOG_TAG = "HardwareRenderer"; + + // Keep in sync with DrawFrameTask.h SYNC_* flags + /** + * Nothing interesting to report. Sync & draw kicked off + */ + public static final int SYNC_OK = 0; + + /** + * The renderer is requesting a redraw. This can occur if there's an animation that's running + * in the RenderNode tree and the hardware renderer is unable to self-animate. + * + * If this is returned from syncAndDrawFrame the expectation is that syncAndDrawFrame + * will be called again on the next vsync signal. + */ + public static final int SYNC_REDRAW_REQUESTED = 1 << 0; + + /** + * The hardware renderer no longer has a valid {@link android.view.Surface} to render to. + * This can happen if {@link Surface#destroy()} was called. The user should no longer + * attempt to call syncAndDrawFrame until a new surface has been provided by calling + * setSurface. + * + * Spoiler: the reward is GPU-accelerated drawing, better find that Surface! + */ + public static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1; + + /** + * The hardware renderer has been set to a "stopped" state. If this is returned then the + * rendering content has been synced, however a frame was not produced. + */ + public static final int SYNC_CONTEXT_IS_STOPPED = 1 << 2; + + /** + * The content was synced but the renderer has declined to produce a frame in this vsync + * interval. This can happen if a frame was already drawn in this vsync or if the renderer + * is outrunning the frame consumer. The renderer will internally re-schedule itself + * to render a frame in the next vsync signal, so the caller does not need to do anything + * in response to this signal. + */ + public static final int SYNC_FRAME_DROPPED = 1 << 3; + + @IntDef(value = { + SYNC_OK, SYNC_REDRAW_REQUESTED, SYNC_LOST_SURFACE_REWARD_IF_FOUND, + SYNC_CONTEXT_IS_STOPPED, SYNC_FRAME_DROPPED}) + @Retention(RetentionPolicy.SOURCE) + public @interface SyncAndDrawResult { + } + + /** @hide */ + public static final int FLAG_DUMP_FRAMESTATS = 1 << 0; + /** @hide */ + public static final int FLAG_DUMP_RESET = 1 << 1; + /** @hide */ + public static final int FLAG_DUMP_ALL = FLAG_DUMP_FRAMESTATS; + + /** @hide */ + @IntDef(flag = true, prefix = {"FLAG_DUMP_"}, value = { + FLAG_DUMP_FRAMESTATS, + FLAG_DUMP_RESET + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DumpFlags { + } + + /** + * Name of the file that holds the shaders cache. + */ + private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache"; + private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache"; + + private final long mNativeProxy; + /** @hide */ + protected RenderNode mRootNode; + private boolean mOpaque = true; + private boolean mForceDark = false; + private FrameInfo mScratchInfo; + + /** + * Creates a new instance of a HardwareRenderer. The HardwareRenderer will default + * to opaque with no light source configured. + */ + public HardwareRenderer() { + mRootNode = RenderNode.adopt(nCreateRootRenderNode()); + mRootNode.setClipToBounds(false); + mNativeProxy = nCreateProxy(!mOpaque, mRootNode.mNativeRenderNode); + if (mNativeProxy == 0) { + throw new OutOfMemoryError("Unable to create hardware renderer"); + } + Cleaner.create(this, new DestroyContextRunnable(mNativeProxy)); + ProcessInitializer.sInstance.init(mNativeProxy); + } + + /** + * Destroys the rendering context of this HardwareRenderer. This destroys the resources + * associated with this renderer and releases the currently set {@link Surface}. + * + * The renderer may be restored from this state by setting a new {@link Surface}, setting + * new rendering content with {@link #setContentRoot(RenderNode)}, and resuming + * rendering with {@link #syncAndDrawFrame(long)}. + * + * It is suggested to call this in response to callbacks such as + * {@link android.view.SurfaceHolder.Callback#surfaceDestroyed(SurfaceHolder)}. + * + * Note that if there are any outstanding frame commit callbacks they may end up never being + * invoked if the frame was deferred to a later vsync. + */ + public void destroy() { + nDestroy(mNativeProxy, mRootNode.mNativeRenderNode); + } + + /** + * Sets a name for this renderer. This is used to identify this renderer instance + * when reporting debug information such as the per-window frame time metrics + * reported by 'adb shell dumpsys gfxinfo [package] framestats' + * + * @param name The debug name to use for this HardwareRenderer instance + */ + public void setName(String name) { + nSetName(mNativeProxy, name); + } + + /** + * Sets the center of the light source. The light source point controls the directionality + * and shape of shadows rendered by RenderNode Z & elevation. + * + * The platform's recommendation is to set lightX to 'displayWidth / 2f - windowLeft', set + * lightY to 0 - windowTop, lightZ set to 600dp, and lightRadius to 800dp. + * + * The light source should be setup both as part of initial configuration, and whenever + * the window moves to ensure the light source stays anchored in display space instead + * of in window space. + * + * This must be set at least once along with {@link #setLightSourceAlpha(float, float)} + * before shadows will work. + * + * @param lightX The X position of the light source + * @param lightY The Y position of the light source + * @param lightZ The Z position of the light source. Must be >= 0. + * @param lightRadius The radius of the light source. Smaller radius will have sharper edges, + * larger radius will have softer shadows. + */ + public void setLightSourceGeometry(float lightX, float lightY, float lightZ, + float lightRadius) { + validateFinite(lightX, "lightX"); + validateFinite(lightY, "lightY"); + validatePositive(lightZ, "lightZ"); + validatePositive(lightRadius, "lightRadius"); + nSetLightGeometry(mNativeProxy, lightX, lightY, lightZ, lightRadius); + } + + /** + * Configures the ambient & spot shadow alphas. This is the alpha used when the shadow + * has max alpha, and ramps down from the values provided to zero. + * + * These values are typically provided by the current theme, see + * {@link android.R.attr#spotShadowAlpha} and {@link android.R.attr#ambientShadowAlpha}. + * + * This must be set at least once along with + * {@link #setLightSourceGeometry(float, float, float, float)} before shadows will work. + * + * @param ambientShadowAlpha The alpha for the ambient shadow. If unsure, a reasonable default + * is 0.039f. + * @param spotShadowAlpha The alpha for the spot shadow. If unsure, a reasonable default is + * 0.19f. + */ + public void setLightSourceAlpha(@FloatRange(from = 0.0f, to = 1.0f) float ambientShadowAlpha, + @FloatRange(from = 0.0f, to = 1.0f) float spotShadowAlpha) { + validateAlpha(ambientShadowAlpha, "ambientShadowAlpha"); + validateAlpha(spotShadowAlpha, "spotShadowAlpha"); + nSetLightAlpha(mNativeProxy, ambientShadowAlpha, spotShadowAlpha); + } + + /** + * Sets the content root to render. It is not necessary to call this whenever the content + * recording changes. Any mutations to the RenderNode content, or any of the RenderNode's + * contained within the content node, will be applied whenever {@link #syncAndDrawFrame(long)} + * is called. + * + * @param content The content to set as the root RenderNode. If null the content root is removed + * and the renderer will draw nothing. + */ + public void setContentRoot(@Nullable RenderNode content) { + RecordingCanvas canvas = mRootNode.startRecording(); + if (content != null) { + canvas.drawRenderNode(content); + } + mRootNode.endRecording(); + } + + /** + * <p>The surface to render into. The surface is assumed to be associated with the display and + * as such is still driven by vsync signals such as those from + * {@link android.view.Choreographer} and that it has a native refresh rate matching that of + * the display's (typically 60hz).</p> + * + * <p>NOTE: Due to the shared, cooperative nature of the render thread it is critical that + * any {@link Surface} used must have a prompt, reliable consuming side. System-provided + * consumers such as {@link android.view.SurfaceView}, + * {@link android.view.Window#takeSurface(SurfaceHolder.Callback2)}, + * or {@link android.view.TextureView} all fit this requirement. However if custom consumers + * are used such as when using {@link SurfaceTexture} or {@link android.media.ImageReader} + * it is the app's responsibility to ensure that they consume updates promptly and rapidly. + * Failure to do so will cause the render thread to stall on that surface, blocking all + * HardwareRenderer instances.</p> + * + * @param surface The surface to render into. If null then rendering will be stopped. If + * non-null then {@link Surface#isValid()} must be true. + */ + public void setSurface(@Nullable Surface surface) { + if (surface != null && !surface.isValid()) { + throw new IllegalArgumentException("Surface is invalid. surface.isValid() == false."); + } + nSetSurface(mNativeProxy, surface); + } + + /** + * Syncs the RenderNode tree to the render thread and requests a frame to be drawn. + * + * @hide + */ + @SyncAndDrawResult + public int syncAndDrawFrame(@NonNull FrameInfo frameInfo) { + return nSyncAndDrawFrame(mNativeProxy, frameInfo.frameInfo, frameInfo.frameInfo.length); + } + + /** + * Syncs the RenderNode tree to the render thread and requests a frame to be drawn. + * + * @param vsyncTime The vsync timestamp for this frame. Typically this comes from + * {@link android.view.Choreographer.FrameCallback}. Must be set and be valid + * as the renderer uses this time internally to drive animations. + * @return The result of the sync operation. See {@link SyncAndDrawResult}. + */ + @SyncAndDrawResult + public int syncAndDrawFrame(long vsyncTime) { + if (mScratchInfo == null) { + mScratchInfo = new FrameInfo(); + } + mScratchInfo.setVsync(vsyncTime, vsyncTime); + mScratchInfo.addFlags(FrameInfo.FLAG_SURFACE_CANVAS); + return syncAndDrawFrame(mScratchInfo); + } + + /** + * Syncs the RenderNode tree to the render thread and requests a frame to be drawn. + * frameCommitCallback callback will be invoked when the current rendering content has been + * rendered into a frame and submitted to the swap chain. + * + * @param vsyncTime The vsync timestamp for this frame. Typically this comes from + * {@link android.view.Choreographer.FrameCallback}. Must be set and + * be valid as the renderer uses this time internally to drive + * animations. + * @param frameCommitCallback The callback to invoke when the frame content has been drawn. + * Will be invoked on the current {@link android.os.Looper} thread. + * @return The result of the sync operation. See {@link SyncAndDrawResult}. + */ + @SyncAndDrawResult + public int syncAndDrawFrame(long vsyncTime, + @Nullable Runnable frameCommitCallback) { + if (frameCommitCallback != null) { + setFrameCompleteCallback(frameNr -> frameCommitCallback.run()); + } + return syncAndDrawFrame(vsyncTime); + } + + /** + * Suspends any current rendering into the surface but do not do any destruction. This + * is useful to temporarily suspend using the active Surface in order to do any Surface + * mutations necessary. + * + * Any subsequent draws will override the pause, resuming normal operation. + * + * @return true if there was an outstanding render request, false otherwise. If this is true + * the caller should ensure that {@link #syncAndDrawFrame(long)} is called at the soonest + * possible time to resume normal operation. + * + * TODO Should this be exposed? ViewRootImpl needs it because it destroys the old + * Surface before getting a new one. However things like SurfaceView will ensure that + * the old surface remains un-destroyed until after a new frame has been produced with + * the new surface. + * @hide + */ + public boolean pause() { + return nPause(mNativeProxy); + } + + /** + * Hard stops rendering into the surface. If the renderer is stopped it will + * block any attempt to render. Calls to {@link #syncAndDrawFrame(long)} will still + * sync over the latest rendering content, however they will not render and instead + * {@link #SYNC_CONTEXT_IS_STOPPED} will be returned. + * + * If false is passed then rendering will resume as normal. Any pending rendering requests + * will produce a new frame at the next vsync signal. + * + * This is useful in combination with lifecycle events such as {@link Activity#onStop()} + * and {@link Activity#onStart()}. + * + * @param stopped true to stop all rendering, false to resume + */ + public void setStopped(boolean stopped) { + nSetStopped(mNativeProxy, stopped); + } + + /** + * Destroys all hardware rendering resources associated with the current rendering content. + * This includes releasing a reference to the current content root RenderNode. It will + * therefore be necessary to call {@link #setContentRoot(RenderNode)} in order to resume + * rendering after calling this. + * + * It is recommended, but not necessary, to use this in combination with lifecycle events + * such as {@link Activity#onStop()} and {@link Activity#onStart()} or in response to + * {@link android.content.ComponentCallbacks2#onTrimMemory(int)} signals such as + * {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} + * + * See also {@link #setStopped(boolean)} + */ + public void destroyHardwareResources() { + nDestroyHardwareResources(mNativeProxy); + } + + /** + * Whether or not the force-dark feature should be used for this renderer. + */ + public boolean setForceDark(boolean enable) { + if (mForceDark != enable) { + mForceDark = enable; + nSetForceDark(mNativeProxy, enable); + return true; + } + return false; + } + + /** + * Allocate buffers ahead of time to avoid allocation delays during rendering. + * + * Typically a Surface will allocate buffers lazily. This is usually fine and reduces the + * memory usage of Surfaces that render rarely or never hit triple buffering. However + * for UI it can result in a slight bit of jank on first launch. This hint will + * tell the HardwareRenderer that now is a good time to allocate the 3 buffers + * necessary for typical rendering. + * + * Must be called after a {@link Surface} has been set. + */ + public void allocateBuffers() { + nAllocateBuffers(mNativeProxy); + } + + /** + * Notifies the hardware renderer that a call to {@link #syncAndDrawFrame(long)} will + * be coming soon. This is used to help schedule when RenderThread-driven animations will + * happen as the renderer wants to avoid producing more than one frame per vsync signal. + */ + public void notifyFramePending() { + nNotifyFramePending(mNativeProxy); + } + + /** + * Change the HardwareRenderer's opacity. Will take effect on the next frame produced. + * + * If the renderer is set to opaque it is the app's responsibility to ensure that the + * content renders to every pixel of the Surface, otherwise corruption may result. Note that + * this includes ensuring that the first draw of any given pixel does not attempt to blend + * against the destination. If this is false then the hardware renderer will clear to + * transparent at the start of every frame. + * + * @param opaque true if the content rendered is opaque, false if the renderer should clear + * to transparent before rendering + */ + public void setOpaque(boolean opaque) { + if (mOpaque != opaque) { + mOpaque = opaque; + nSetOpaque(mNativeProxy, mOpaque); + } + } + + /** + * Whether or not the renderer is set to be opaque. See {@link #setOpaque(boolean)} + * + * @return true if the renderer is opaque, false otherwise + */ + public boolean isOpaque() { + return mOpaque; + } + + /** @hide */ + public void setFrameCompleteCallback(FrameCompleteCallback callback) { + nSetFrameCompleteCallback(mNativeProxy, callback); + } + + /** + * TODO: Public API this? + * + * @hide + */ + public void addFrameMetricsObserver(FrameMetricsObserver observer) { + long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer); + observer.mNative = new VirtualRefBasePtr(nativeObserver); + } + + /** + * TODO: Public API this? + * + * @hide + */ + public void removeFrameMetricsObserver(FrameMetricsObserver observer) { + nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get()); + observer.mNative = null; + } + + /** + * Enable/disable wide gamut rendering on this renderer. Whether or not the actual rendering + * will be wide gamut depends on the hardware support for such rendering. + * + * @param wideGamut true if this renderer should render in wide gamut, false if it should + * render in sRGB + * TODO: Figure out color... + * @hide + */ + public void setWideGamut(boolean wideGamut) { + nSetWideGamut(mNativeProxy, wideGamut); + } + + /** + * Blocks until all previously queued work has completed. + * + * TODO: Only used for draw finished listeners, but the FrameCompleteCallback does that + * better + * + * @hide + */ + public void fence() { + nFence(mNativeProxy); + } + + /** @hide */ + public void registerAnimatingRenderNode(RenderNode animator) { + nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode); + } + + /** @hide */ + public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) { + nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode, + animator.getAnimatorNativePtr()); + } + + /** + * Prevents any further drawing until {@link #syncAndDrawFrame(long)} is called. + * This is a signal that the contents of the RenderNode tree are no longer safe to play back. + * In practice this usually means that there are Functor pointers in the + * display list that are no longer valid. + * + * TODO: Can we get webview off of this? + * + * @hide + */ + public void stopDrawing() { + nStopDrawing(mNativeProxy); + } + + /** + * Creates a new hardware layer. A hardware layer built by calling this + * method will be treated as a texture layer, instead of as a render target. + * + * @return A hardware layer + * @hide + */ + public TextureLayer createTextureLayer() { + long layer = nCreateTextureLayer(mNativeProxy); + return TextureLayer.adoptTextureLayer(this, layer); + } + + /** + * Detaches the layer's surface texture from the GL context and releases + * the texture id + * + * @hide + */ + public void detachSurfaceTexture(long hardwareLayer) { + nDetachSurfaceTexture(mNativeProxy, hardwareLayer); + } + + + /** @hide */ + public void buildLayer(RenderNode node) { + if (node.hasDisplayList()) { + nBuildLayer(mNativeProxy, node.mNativeRenderNode); + } + } + + /** @hide */ + public boolean copyLayerInto(final TextureLayer layer, final Bitmap bitmap) { + return nCopyLayerInto(mNativeProxy, + layer.getDeferredLayerUpdater(), bitmap); + } + + /** + * Indicates that the specified hardware layer needs to be updated + * as soon as possible. + * + * @param layer The hardware layer that needs an update + * @hide + */ + public void pushLayerUpdate(TextureLayer layer) { + nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); + } + + /** + * Tells the HardwareRenderer that the layer is destroyed. The renderer + * should remove the layer from any update queues. + * + * @hide + */ + public void onLayerDestroyed(TextureLayer layer) { + nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); + } + + /** @hide */ + public void setFrameCallback(FrameDrawingCallback callback) { + nSetFrameCallback(mNativeProxy, callback); + } + + /** + * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the + * rendernode of the UI thread. + * + * @param node The node to add. + * @param placeFront If true, the render node will be placed in front of the content node, + * otherwise behind the content node. + * @hide + */ + public void addRenderNode(RenderNode node, boolean placeFront) { + nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront); + } + + /** + * Only especially added render nodes can be removed. + * + * @param node The node which was added via addRenderNode which should get removed again. + * @hide + */ + public void removeRenderNode(RenderNode node) { + nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode); + } + + /** + * Draws a particular render node. If the node is not the content node, only the additional + * nodes will get drawn and the content remains untouched. + * + * @param node The node to be drawn. + * @hide + */ + public void drawRenderNode(RenderNode node) { + nDrawRenderNode(mNativeProxy, node.mNativeRenderNode); + } + + /** + * Loads system properties used by the renderer. This method is invoked + * whenever system properties are modified. Implementations can use this + * to trigger live updates of the renderer based on properties. + * + * @return True if a property has changed. + * @hide + */ + public boolean loadSystemProperties() { + return nLoadSystemProperties(mNativeProxy); + } + + /** + * @hide + */ + public void dumpProfileInfo(FileDescriptor fd, @DumpFlags int dumpFlags) { + nDumpProfileInfo(mNativeProxy, fd, dumpFlags); + } + + /** + * To avoid unnecessary overdrawing of the main content all additionally passed render nodes + * will be prevented to overdraw this area. It will be synchronized with the draw call. + * This should be updated in the content view's draw call. + * + * @param left The left side of the protected bounds. + * @param top The top side of the protected bounds. + * @param right The right side of the protected bounds. + * @param bottom The bottom side of the protected bounds. + * @hide + */ + public void setContentDrawBounds(int left, int top, int right, int bottom) { + nSetContentDrawBounds(mNativeProxy, left, top, right, bottom); + } + + /** + * Interface used to receive callbacks when a frame is being drawn. + * + * @hide + */ + public interface FrameDrawingCallback { + /** + * Invoked during a frame drawing. + * + * @param frame The id of the frame being drawn. + */ + void onFrameDraw(long frame); + } + + /** + * Interface used to be notified when a frame has finished rendering + * + * @hide + */ + public interface FrameCompleteCallback { + /** + * Invoked after a frame draw + * + * @param frameNr The id of the frame that was drawn. + */ + void onFrameComplete(long frameNr); + } + + private static void validateAlpha(float alpha, String argumentName) { + if (!(alpha >= 0.0f && alpha <= 1.0f)) { + throw new IllegalArgumentException(argumentName + " must be a valid alpha, " + + alpha + " is not in the range of 0.0f to 1.0f"); + } + } + + private static void validatePositive(float f, String argumentName) { + if (!(Float.isFinite(f) && f >= 0.0f)) { + throw new IllegalArgumentException(argumentName + + " must be a finite positive, given=" + f); + } + } + + private static void validateFinite(float f, String argumentName) { + if (!Float.isFinite(f)) { + throw new IllegalArgumentException(argumentName + " must be finite, given=" + f); + } + } + + /** @hide */ + public static void invokeFunctor(long functor, boolean waitForCompletion) { + nInvokeFunctor(functor, waitForCompletion); + } + + /** + * b/68769804: For low FPS experiments. + * + * @hide + */ + public static void setFPSDivisor(int divisor) { + nHackySetRTAnimationsEnabled(divisor <= 1); + } + + /** + * Changes the OpenGL context priority if IMG_context_priority extension is available. Must be + * called before any OpenGL context is created. + * + * @param priority The priority to use. Must be one of EGL_CONTEXT_PRIORITY_* values. + * @hide + */ + public static void setContextPriority(int priority) { + nSetContextPriority(priority); + } + + /** + * Sets whether or not high contrast text rendering is enabled. The setting is global + * but only affects content rendered after the change is made. + * + * @hide + */ + public static void setHighContrastText(boolean highContrastText) { + nSetHighContrastText(highContrastText); + } + + /** + * If set RenderThread will avoid doing any IPC using instead a fake vsync & DisplayInfo source + * + * @hide + */ + public static void setIsolatedProcess(boolean isIsolated) { + nSetIsolatedProcess(isIsolated); + } + + /** + * If set extra graphics debugging abilities will be enabled such as dumping skp + * + * @hide + */ + public static void setDebuggingEnabled(boolean enable) { + nSetDebuggingEnabled(enable); + } + + /** @hide */ + public static int copySurfaceInto(Surface surface, Rect srcRect, Bitmap bitmap) { + if (srcRect == null) { + // Empty rect means entire surface + return nCopySurfaceInto(surface, 0, 0, 0, 0, bitmap); + } else { + return nCopySurfaceInto(surface, srcRect.left, srcRect.top, + srcRect.right, srcRect.bottom, bitmap); + } + } + + /** + * Creates a {@link android.graphics.Bitmap.Config#HARDWARE} bitmap from the given + * RenderNode. Note that the RenderNode should be created as a root node (so x/y of 0,0), and + * not the RenderNode from a View. + * + * @hide + **/ + public static Bitmap createHardwareBitmap(RenderNode node, int width, int height) { + return nCreateHardwareBitmap(node.mNativeRenderNode, width, height); + } + + /** + * Invoke this method when the system is running out of memory. This + * method will attempt to recover as much memory as possible, based on + * the specified hint. + * + * @param level Hint about the amount of memory that should be trimmed, + * see {@link android.content.ComponentCallbacks} + * @hide + */ + public static void trimMemory(int level) { + nTrimMemory(level); + } + + /** @hide */ + public static void overrideProperty(@NonNull String name, @NonNull String value) { + if (name == null || value == null) { + throw new IllegalArgumentException("name and value must be non-null"); + } + nOverrideProperty(name, value); + } + + /** + * Sets the directory to use as a persistent storage for threaded rendering + * resources. + * + * @param cacheDir A directory the current process can write to + * @hide + */ + public static void setupDiskCache(File cacheDir) { + setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(), + new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath()); + } + + /** @hide */ + public static void setPackageName(String packageName) { + ProcessInitializer.sInstance.setPackageName(packageName); + } + + private static final class DestroyContextRunnable implements Runnable { + private final long mNativeInstance; + + DestroyContextRunnable(long nativeInstance) { + mNativeInstance = nativeInstance; + } + + @Override + public void run() { + nDeleteProxy(mNativeInstance); + } + } + + private static class ProcessInitializer { + static ProcessInitializer sInstance = new ProcessInitializer(); + + private boolean mInitialized = false; + + private String mPackageName; + private IGraphicsStats mGraphicsStatsService; + private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() { + @Override + public void onRotateGraphicsStatsBuffer() throws RemoteException { + rotateBuffer(); + } + }; + + private ProcessInitializer() { + } + + synchronized void setPackageName(String name) { + if (mInitialized) return; + mPackageName = name; + } + + synchronized void init(long renderProxy) { + if (mInitialized) return; + mInitialized = true; + + initSched(renderProxy); + initGraphicsStats(); + } + + private void initSched(long renderProxy) { + try { + int tid = nGetRenderThreadTid(renderProxy); + ActivityManager.getService().setRenderThread(tid); + } catch (Throwable t) { + Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t); + } + } + + private void initGraphicsStats() { + if (mPackageName == null) return; + + try { + IBinder binder = ServiceManager.getService("graphicsstats"); + if (binder == null) return; + mGraphicsStatsService = IGraphicsStats.Stub.asInterface(binder); + requestBuffer(); + } catch (Throwable t) { + Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t); + } + } + + private void rotateBuffer() { + nRotateProcessStatsBuffer(); + requestBuffer(); + } + + private void requestBuffer() { + try { + ParcelFileDescriptor pfd = mGraphicsStatsService + .requestBufferForProcess(mPackageName, mGraphicsStatsCallback); + nSetProcessStatsBuffer(pfd.getFd()); + pfd.close(); + } catch (Throwable t) { + Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t); + } + } + } + + /** + * @hide + */ + public static native void disableVsync(); + + /** @hide */ + protected static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile); + + private static native void nRotateProcessStatsBuffer(); + + private static native void nSetProcessStatsBuffer(int fd); + + private static native int nGetRenderThreadTid(long nativeProxy); + + private static native long nCreateRootRenderNode(); + + private static native long nCreateProxy(boolean translucent, long rootRenderNode); + + private static native void nDeleteProxy(long nativeProxy); + + private static native boolean nLoadSystemProperties(long nativeProxy); + + private static native void nSetName(long nativeProxy, String name); + + private static native void nSetSurface(long nativeProxy, Surface window); + + private static native boolean nPause(long nativeProxy); + + private static native void nSetStopped(long nativeProxy, boolean stopped); + + private static native void nSetLightGeometry(long nativeProxy, + float lightX, float lightY, float lightZ, float lightRadius); + + private static native void nSetLightAlpha(long nativeProxy, float ambientShadowAlpha, + float spotShadowAlpha); + + private static native void nSetOpaque(long nativeProxy, boolean opaque); + + private static native void nSetWideGamut(long nativeProxy, boolean wideGamut); + + private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size); + + private static native void nDestroy(long nativeProxy, long rootRenderNode); + + private static native void nRegisterAnimatingRenderNode(long rootRenderNode, + long animatingNode); + + private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator); + + private static native void nInvokeFunctor(long functor, boolean waitForCompletion); + + private static native long nCreateTextureLayer(long nativeProxy); + + private static native void nBuildLayer(long nativeProxy, long node); + + private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap); + + private static native void nPushLayerUpdate(long nativeProxy, long layer); + + private static native void nCancelLayerUpdate(long nativeProxy, long layer); + + private static native void nDetachSurfaceTexture(long nativeProxy, long layer); + + private static native void nDestroyHardwareResources(long nativeProxy); + + private static native void nTrimMemory(int level); + + private static native void nOverrideProperty(String name, String value); + + private static native void nFence(long nativeProxy); + + private static native void nStopDrawing(long nativeProxy); + + private static native void nNotifyFramePending(long nativeProxy); + + private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd, + @DumpFlags int dumpFlags); + + private static native void nAddRenderNode(long nativeProxy, long rootRenderNode, + boolean placeFront); + + private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode); + + private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode); + + private static native void nSetContentDrawBounds(long nativeProxy, int left, + int top, int right, int bottom); + + private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback); + + private static native void nSetFrameCompleteCallback(long nativeProxy, + FrameCompleteCallback callback); + + private static native long nAddFrameMetricsObserver(long nativeProxy, + FrameMetricsObserver observer); + + private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver); + + private static native int nCopySurfaceInto(Surface surface, + int srcLeft, int srcTop, int srcRight, int srcBottom, Bitmap bitmap); + + private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height); + + private static native void nSetHighContrastText(boolean enabled); + + // For temporary experimentation b/66945974 + private static native void nHackySetRTAnimationsEnabled(boolean enabled); + + private static native void nSetDebuggingEnabled(boolean enabled); + + private static native void nSetIsolatedProcess(boolean enabled); + + private static native void nSetContextPriority(int priority); + + private static native void nAllocateBuffers(long nativeProxy); + + private static native void nSetForceDark(long nativeProxy, boolean enabled); +} diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp index 236a6b667f3b..b04c77430367 100644 --- a/libs/hwui/FrameInfoVisualizer.cpp +++ b/libs/hwui/FrameInfoVisualizer.cpp @@ -66,6 +66,7 @@ static int dpToPx(int dp, float density) { FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) : mFrameSource(source) { setDensity(1); + consumeProperties(); } FrameInfoVisualizer::~FrameInfoVisualizer() { diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 92a749f3da33..f1a522ecd588 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -180,14 +180,20 @@ void CanvasContext::setStopped(bool stopped) { } } -void CanvasContext::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { - mLightGeometry.radius = lightRadius; +void CanvasContext::allocateBuffers() { + if (mNativeSurface) { + mNativeSurface->allocateBuffers(); + } +} + +void CanvasContext::setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { mLightInfo.ambientShadowAlpha = ambientShadowAlpha; mLightInfo.spotShadowAlpha = spotShadowAlpha; } -void CanvasContext::setLightCenter(const Vector3& lightCenter) { +void CanvasContext::setLightGeometry(const Vector3& lightCenter, float lightRadius) { mLightGeometry.center = lightCenter; + mLightGeometry.radius = lightRadius; } void CanvasContext::setOpaque(bool opaque) { diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 2307ee4801d3..70be4a6d7730 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -113,9 +113,10 @@ public: bool pauseSurface(); void setStopped(bool stopped); bool hasSurface() { return mNativeSurface.get(); } + void allocateBuffers(); - void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); - void setLightCenter(const Vector3& lightCenter); + void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); + void setLightGeometry(const Vector3& lightCenter, float lightRadius); void setOpaque(bool opaque); void setWideGamut(bool wideGamut); bool makeCurrent(); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 54219b5a1489..085812a00f71 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -80,22 +80,16 @@ void RenderProxy::setName(const char* name) { mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); }); } -void RenderProxy::initialize(const sp<Surface>& surface) { +void RenderProxy::setSurface(const sp<Surface>& surface) { mRenderThread.queue().post( [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); }); } -void RenderProxy::allocateBuffers(const sp<Surface>& surface) { - mRenderThread.queue().post( - [ surf = surface ]() mutable { surf->allocateBuffers(); }); -} - -void RenderProxy::updateSurface(const sp<Surface>& surface) { - mRenderThread.queue().post( - [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); }); +void RenderProxy::allocateBuffers() { + mRenderThread.queue().post([=]() { mContext->allocateBuffers(); }); } -bool RenderProxy::pauseSurface(const sp<Surface>& surface) { +bool RenderProxy::pause() { return mRenderThread.queue().runSync([this]() -> bool { return mContext->pauseSurface(); }); } @@ -103,13 +97,13 @@ void RenderProxy::setStopped(bool stopped) { mRenderThread.queue().runSync([this, stopped]() { mContext->setStopped(stopped); }); } -void RenderProxy::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { +void RenderProxy::setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { mRenderThread.queue().post( - [=]() { mContext->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha); }); + [=]() { mContext->setLightAlpha(ambientShadowAlpha, spotShadowAlpha); }); } -void RenderProxy::setLightCenter(const Vector3& lightCenter) { - mRenderThread.queue().post([=]() { mContext->setLightCenter(lightCenter); }); +void RenderProxy::setLightGeometry(const Vector3& lightCenter, float lightRadius) { + mRenderThread.queue().post([=]() { mContext->setLightGeometry(lightCenter, lightRadius); }); } void RenderProxy::setOpaque(bool opaque) { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index d29fcc49d7a6..6668c5840c3e 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -69,13 +69,12 @@ public: ANDROID_API bool loadSystemProperties(); ANDROID_API void setName(const char* name); - ANDROID_API void initialize(const sp<Surface>& surface); - ANDROID_API void allocateBuffers(const sp<Surface>& surface); - ANDROID_API void updateSurface(const sp<Surface>& surface); - ANDROID_API bool pauseSurface(const sp<Surface>& surface); + ANDROID_API void setSurface(const sp<Surface>& surface); + ANDROID_API void allocateBuffers(); + ANDROID_API bool pause(); ANDROID_API void setStopped(bool stopped); - ANDROID_API void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); - ANDROID_API void setLightCenter(const Vector3& lightCenter); + ANDROID_API void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); + ANDROID_API void setLightGeometry(const Vector3& lightCenter, float lightRadius); ANDROID_API void setOpaque(bool opaque); ANDROID_API void setWideGamut(bool wideGamut); ANDROID_API int64_t* frameInfo(); diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 62f704b08771..2384f9541ec0 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -74,7 +74,7 @@ class RenderThread : private ThreadBase { PREVENT_COPY_AND_ASSIGN(RenderThread); public: - // Sets a callback that fires before any RenderThread setup has occured. + // Sets a callback that fires before any RenderThread setup has occurred. ANDROID_API static void setOnStartHook(void (*onStartHook)()); WorkQueue& queue() { return ThreadBase::queue(); } diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp index 5f5a92e55bf2..5fa008b5b4df 100644 --- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp +++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp @@ -132,10 +132,10 @@ void run(const TestScene::Info& info, const TestScene::Options& opts, ContextFactory factory; std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode.get(), &factory)); proxy->loadSystemProperties(); - proxy->initialize(surface); + proxy->setSurface(surface); float lightX = width / 2.0; - proxy->setup(dp(800.0f), 255 * 0.075, 255 * 0.15); - proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)}); + proxy->setLightAlpha(255 * 0.075, 255 * 0.15); + proxy->setLightGeometry((Vector3){lightX, dp(-200.0f), dp(800.0f)}, dp(800.0f)); // Do a few cold runs then reset the stats so that the caches are all hot int warmupFrameCount = 5; |