| /* | |
| * 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.content.Context; | |
| import android.content.pm.ActivityInfo; | |
| import android.content.res.Configuration; | |
| import android.hardware.DataSpace; | |
| import android.hardware.HardwareBuffer; | |
| import android.hardware.OverlayProperties; | |
| import android.hardware.display.DisplayManager; | |
| import android.os.IBinder; | |
| import android.os.ParcelFileDescriptor; | |
| import android.os.RemoteException; | |
| import android.os.ServiceManager; | |
| import android.util.Log; | |
| import android.util.TimeUtils; | |
| import android.view.Display; | |
| import android.view.Display.Mode; | |
| import android.view.IGraphicsStats; | |
| import android.view.IGraphicsStatsCallback; | |
| import android.view.NativeVectorDrawableAnimator; | |
| import android.view.PixelCopy; | |
| import android.view.Surface; | |
| import android.view.SurfaceControl; | |
| import android.view.SurfaceHolder; | |
| import android.view.animation.AnimationUtils; | |
| import java.io.File; | |
| import java.io.FileDescriptor; | |
| import java.lang.annotation.Retention; | |
| import java.lang.annotation.RetentionPolicy; | |
| import java.util.concurrent.Executor; | |
| 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>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> | |
| */ | |
| 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. | |
| * | |
| * <p>If this is returned from syncAndDraw the expectation is that syncAndDraw | |
| * 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#release()} was called. The user should no longer | |
| * attempt to call syncAndDraw until a new surface has been provided by calling | |
| * setSurface. | |
| * | |
| * <p>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; | |
| /** @hide */ | |
| @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 { | |
| } | |
| /** | |
| * Trims all Skia caches. | |
| * @hide | |
| */ | |
| public static final int CACHE_TRIM_ALL = 0; | |
| /** | |
| * Trims Skia font caches. | |
| * @hide | |
| */ | |
| public static final int CACHE_TRIM_FONT = 1; | |
| /** | |
| * Trims Skia resource caches. | |
| * @hide | |
| */ | |
| public static final int CACHE_TRIM_RESOURCES = 2; | |
| /** @hide */ | |
| @IntDef(prefix = {"CACHE_TRIM_"}, value = { | |
| CACHE_TRIM_ALL, | |
| CACHE_TRIM_FONT, | |
| CACHE_TRIM_RESOURCES | |
| }) | |
| @Retention(RetentionPolicy.SOURCE) | |
| public @interface CacheTrimLevel {} | |
| /** | |
| * 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 static int sDensityDpi = 0; | |
| private final long mNativeProxy; | |
| /** @hide */ | |
| protected RenderNode mRootNode; | |
| private boolean mOpaque = true; | |
| private int mForceDark = ForceDarkType.NONE; | |
| private @ActivityInfo.ColorMode int mColorMode = ActivityInfo.COLOR_MODE_DEFAULT; | |
| private float mDesiredSdrHdrRatio = 1f; | |
| /** | |
| * Creates a new instance of a HardwareRenderer. The HardwareRenderer will default | |
| * to opaque with no light source configured. | |
| */ | |
| public HardwareRenderer() { | |
| ProcessInitializer.sInstance.initUsingContext(); | |
| 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}. This must | |
| * be called when this HardwareRenderer is no longer needed. | |
| * | |
| * <p>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 by issuing a new {@link FrameRenderRequest}. | |
| * | |
| * <p>It is recommended to call this in response to callbacks such as | |
| * {@link android.view.SurfaceHolder.Callback#surfaceDestroyed(SurfaceHolder)}. | |
| * | |
| * <p>Note that if there are any outstanding frame commit callbacks they may 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(@NonNull 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. | |
| * | |
| * <p>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. | |
| * | |
| * <p>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. | |
| * | |
| * <p>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. | |
| * | |
| * <p>These values are typically provided by the current theme, see | |
| * {@link android.R.attr#spotShadowAlpha} and {@link android.R.attr#ambientShadowAlpha}. | |
| * | |
| * <p>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 a new {@link FrameRenderRequest} | |
| * is issued via {@link #createRenderRequest()} and {@link FrameRenderRequest#syncAndDraw()}. | |
| * | |
| * @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.beginRecording(); | |
| 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) { | |
| setSurface(surface, false); | |
| } | |
| /** | |
| * See {@link #setSurface(Surface)} | |
| * | |
| * @hide | |
| * @param discardBuffer determines whether the surface will attempt to preserve its contents | |
| * between frames. If set to true the renderer will attempt to preserve | |
| * the contents of the buffer between frames if the implementation allows | |
| * it. If set to false no attempt will be made to preserve the buffer's | |
| * contents between frames. | |
| */ | |
| public void setSurface(@Nullable Surface surface, boolean discardBuffer) { | |
| if (surface != null && !surface.isValid()) { | |
| throw new IllegalArgumentException("Surface is invalid. surface.isValid() == false."); | |
| } | |
| nSetSurface(mNativeProxy, surface, discardBuffer); | |
| } | |
| /** | |
| * Sets the SurfaceControl to be used internally inside render thread | |
| * @hide | |
| * @param surfaceControl The surface control to pass to render thread in hwui. | |
| * If null, any previous references held in render thread will be discarded. | |
| */ | |
| public void setSurfaceControl(@Nullable SurfaceControl surfaceControl, | |
| @Nullable BLASTBufferQueue blastBufferQueue) { | |
| nSetSurfaceControl(mNativeProxy, surfaceControl != null ? surfaceControl.mNativeObject : 0); | |
| } | |
| /** | |
| * Sets the parameters that can be used to control a render request for a | |
| * {@link HardwareRenderer}. This is not thread-safe and must not be held on to for longer | |
| * than a single frame request. | |
| */ | |
| public final class FrameRenderRequest { | |
| private FrameInfo mFrameInfo = new FrameInfo(); | |
| private boolean mWaitForPresent; | |
| private FrameRenderRequest() { } | |
| private void reset() { | |
| mWaitForPresent = false; | |
| // Default to the animation time which, if choreographer is in play, will default to the | |
| // current vsync time. Otherwise it will be 'now'. | |
| mRenderRequest.setVsyncTime( | |
| AnimationUtils.currentAnimationTimeMillis() * TimeUtils.NANOS_PER_MS); | |
| } | |
| /** @hide */ | |
| public void setFrameInfo(FrameInfo info) { | |
| System.arraycopy(info.frameInfo, 0, mFrameInfo.frameInfo, 0, info.frameInfo.length); | |
| } | |
| /** | |
| * Sets the vsync time that represents the start point of this frame. Typically this | |
| * comes from {@link android.view.Choreographer.FrameCallback}. Other compatible time | |
| * sources include {@link System#nanoTime()}, however if the result is being displayed | |
| * on-screen then using {@link android.view.Choreographer} is strongly recommended to | |
| * ensure smooth animations. | |
| * | |
| * <p>If the clock source is not from a CLOCK_MONOTONIC source then any animations driven | |
| * directly by RenderThread will not be synchronized properly with the current frame. | |
| * | |
| * @param vsyncTime The vsync timestamp for this frame. The timestamp is in nanoseconds | |
| * and should come from a CLOCK_MONOTONIC source. | |
| * | |
| * @return this instance | |
| */ | |
| public @NonNull FrameRenderRequest setVsyncTime(long vsyncTime) { | |
| // TODO(b/168552873): populate vsync Id once available to Choreographer public API | |
| mFrameInfo.setVsync(vsyncTime, vsyncTime, FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, | |
| vsyncTime, -1); | |
| mFrameInfo.addFlags(FrameInfo.FLAG_SURFACE_CANVAS); | |
| return this; | |
| } | |
| /** | |
| * Adds a frame commit callback. This callback will be invoked when the current rendering | |
| * content has been rendered into a frame and submitted to the swap chain. The frame may | |
| * not currently be visible on the display when this is invoked, but it has been submitted. | |
| * This callback is useful in combination with {@link PixelCopy} to capture the current | |
| * rendered content of the UI reliably. | |
| * | |
| * @param executor The executor to run the callback on. It is strongly recommended that | |
| * this executor post to a different thread, as the calling thread is | |
| * highly sensitive to being blocked. | |
| * @param frameCommitCallback The callback to invoke when the frame content has been drawn. | |
| * Will be invoked on the given {@link Executor}. | |
| * | |
| * @return this instance | |
| */ | |
| public @NonNull FrameRenderRequest setFrameCommitCallback(@NonNull Executor executor, | |
| @NonNull Runnable frameCommitCallback) { | |
| nSetFrameCommitCallback(mNativeProxy, | |
| didProduceBuffer -> executor.execute(frameCommitCallback)); | |
| return this; | |
| } | |
| /** | |
| * Sets whether or not {@link #syncAndDraw()} should block until the frame has been | |
| * presented. If this is true and {@link #syncAndDraw()} does not return | |
| * {@link #SYNC_FRAME_DROPPED} or an error then when {@link #syncAndDraw()} has returned | |
| * the frame has been submitted to the {@link Surface}. The default and typically | |
| * recommended value is false, as blocking for present will prevent pipelining from | |
| * happening, reducing overall throughput. This is useful for situations such as | |
| * {@link SurfaceHolder.Callback2#surfaceRedrawNeeded(SurfaceHolder)} where it is desired | |
| * to block until a frame has been presented to ensure first-frame consistency with | |
| * other Surfaces. | |
| * | |
| * @param shouldWait If true the next call to {@link #syncAndDraw()} will block until | |
| * completion. | |
| * @return this instance | |
| */ | |
| public @NonNull FrameRenderRequest setWaitForPresent(boolean shouldWait) { | |
| mWaitForPresent = shouldWait; | |
| return this; | |
| } | |
| /** | |
| * Syncs the RenderNode tree to the render thread and requests a frame to be drawn. This | |
| * {@link FrameRenderRequest} instance should no longer be used after calling this method. | |
| * The system internally may reuse instances of {@link FrameRenderRequest} to reduce | |
| * allocation churn. | |
| * | |
| * @return The result of the sync operation. | |
| */ | |
| @SyncAndDrawResult | |
| public int syncAndDraw() { | |
| int syncResult = syncAndDrawFrame(mFrameInfo); | |
| if (mWaitForPresent && (syncResult & SYNC_FRAME_DROPPED) == 0) { | |
| fence(); | |
| } | |
| return syncResult; | |
| } | |
| } | |
| private FrameRenderRequest mRenderRequest = new FrameRenderRequest(); | |
| /** | |
| * Returns a {@link FrameRenderRequest} that can be used to render a new frame. This is used | |
| * to synchronize the RenderNode content provided by {@link #setContentRoot(RenderNode)} with | |
| * the RenderThread and then renders a single frame to the Surface set with | |
| * {@link #setSurface(Surface)}. | |
| * | |
| * @return An instance of {@link FrameRenderRequest}. The instance may be reused for every | |
| * frame, so the caller should not hold onto it for longer than a single render request. | |
| */ | |
| public @NonNull FrameRenderRequest createRenderRequest() { | |
| mRenderRequest.reset(); | |
| return mRenderRequest; | |
| } | |
| /** | |
| * 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); | |
| } | |
| /** | |
| * 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. | |
| * | |
| * <p>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 #createRenderRequest()} | |
| * and {@link FrameRenderRequest#syncAndDraw()} 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 FrameRenderRequest#syncAndDraw()} will | |
| * still sync over the latest rendering content, however they will not render and instead | |
| * {@link #SYNC_CONTEXT_IS_STOPPED} will be returned. | |
| * | |
| * <p>If false is passed then rendering will resume as normal. Any pending rendering requests | |
| * will produce a new frame at the next vsync signal. | |
| * | |
| * <p>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 | |
| * @hide | |
| */ | |
| public void setStopped(boolean stopped) { | |
| nSetStopped(mNativeProxy, stopped); | |
| } | |
| /** | |
| * Hard stops rendering into the surface. If the renderer is stopped it will | |
| * block any attempt to render. Calls to {@link FrameRenderRequest#syncAndDraw()} will | |
| * still sync over the latest rendering content, however they will not render and instead | |
| * {@link #SYNC_CONTEXT_IS_STOPPED} will be returned. | |
| * | |
| * <p>This is useful in combination with lifecycle events such as {@link Activity#onStop()}. | |
| * See {@link #start()} for resuming rendering. | |
| */ | |
| public void stop() { | |
| nSetStopped(mNativeProxy, true); | |
| } | |
| /** | |
| * Resumes rendering into the surface. Any pending rendering requests | |
| * will produce a new frame at the next vsync signal. | |
| * | |
| * <p>This is useful in combination with lifecycle events such as {@link Activity#onStart()}. | |
| * See {@link #stop()} for stopping rendering. | |
| */ | |
| public void start() { | |
| nSetStopped(mNativeProxy, false); | |
| } | |
| /** | |
| * Destroys all the display lists 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, along with re-recording the display lists for the | |
| * RenderNode tree. | |
| * | |
| * <p>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 #stop()}. | |
| */ | |
| public void clearContent() { | |
| nDestroyHardwareResources(mNativeProxy); | |
| } | |
| /** | |
| * Whether or not the force-dark feature should be used for this renderer. | |
| * @hide | |
| */ | |
| public boolean setForceDark(@ForceDarkType.ForceDarkTypeDef int type) { | |
| if (mForceDark != type) { | |
| mForceDark = type; | |
| nSetForceDark(mNativeProxy, type); | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** | |
| * Allocate buffers ahead of time to avoid allocation delays during rendering. | |
| * | |
| * <p>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. | |
| * | |
| * <p>Must be called after a {@link Surface} has been set. | |
| * | |
| * TODO: Figure out if we even need/want this. Should HWUI just be doing this in response | |
| * to setSurface anyway? Vulkan swapchain makes this murky, so delay making it public | |
| * @hide | |
| */ | |
| public void allocateBuffers() { | |
| nAllocateBuffers(mNativeProxy); | |
| } | |
| /** | |
| * Notifies the hardware renderer that a call to {@link FrameRenderRequest#syncAndDraw()} 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. | |
| * | |
| * <p>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 setFrameCommitCallback(FrameCommitCallback callback) { | |
| nSetFrameCommitCallback(mNativeProxy, callback); | |
| } | |
| /** @hide */ | |
| public void setFrameCompleteCallback(FrameCompleteCallback callback) { | |
| nSetFrameCompleteCallback(mNativeProxy, callback); | |
| } | |
| /** | |
| * TODO: Public API this? | |
| * | |
| * @hide | |
| */ | |
| public void addObserver(HardwareRendererObserver observer) { | |
| nAddObserver(mNativeProxy, observer.getNativeInstance()); | |
| } | |
| /** | |
| * TODO: Public API this? | |
| * | |
| * @hide | |
| */ | |
| public void removeObserver(HardwareRendererObserver observer) { | |
| nRemoveObserver(mNativeProxy, observer.getNativeInstance()); | |
| } | |
| /** | |
| * Sets the desired color mode on this renderer. Whether or not the actual rendering | |
| * will use the requested colorMode depends on the hardware support for such rendering. | |
| * | |
| * @param colorMode The @{@link ActivityInfo.ColorMode} to request | |
| * @hide | |
| */ | |
| public float setColorMode(@ActivityInfo.ColorMode int colorMode) { | |
| if (mColorMode != colorMode) { | |
| mColorMode = colorMode; | |
| mDesiredSdrHdrRatio = nSetColorMode(mNativeProxy, colorMode); | |
| } | |
| return mDesiredSdrHdrRatio; | |
| } | |
| /** | |
| * Sets the colormode with the desired SDR white point. | |
| * | |
| * The white point only applies if the color mode is an HDR mode | |
| * | |
| * @hide | |
| */ | |
| public void setColorMode(@ActivityInfo.ColorMode int colorMode, float whitePoint) { | |
| nSetSdrWhitePoint(mNativeProxy, whitePoint); | |
| mColorMode = colorMode; | |
| nSetColorMode(mNativeProxy, colorMode); | |
| } | |
| /** @hide */ | |
| public void setTargetHdrSdrRatio(float ratio) { | |
| if (ratio < 1.f || !Float.isFinite(ratio)) ratio = 1.f; | |
| nSetTargetSdrHdrRatio(mNativeProxy, ratio); | |
| } | |
| /** | |
| * 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 FrameRenderRequest#syncAndDraw()} 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.getNativeInstance()); | |
| } | |
| /** | |
| * 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 */ | |
| protected void setASurfaceTransactionCallback(ASurfaceTransactionCallback callback) { | |
| nSetASurfaceTransactionCallback(mNativeProxy, callback); | |
| } | |
| /** @hide */ | |
| protected void setPrepareSurfaceControlForWebviewCallback( | |
| PrepareSurfaceControlForWebviewCallback callback) { | |
| nSetPrepareSurfaceControlForWebviewCallback(mNativeProxy, callback); | |
| } | |
| /** @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 static void dumpGlobalProfileInfo(FileDescriptor fd, @DumpFlags int dumpFlags) { | |
| nDumpGlobalProfileInfo(fd, dumpFlags); | |
| } | |
| /** | |
| * @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); | |
| } | |
| /** | |
| * Force the new frame to draw, ensuring the UI draw request will attempt a draw this vsync. | |
| * @hide | |
| */ | |
| public void forceDrawNextFrame() { | |
| nForceDrawNextFrame(mNativeProxy); | |
| } | |
| /** @hide */ | |
| public void setPictureCaptureCallback(@Nullable PictureCapturedCallback callback) { | |
| nSetPictureCaptureCallback(mNativeProxy, callback); | |
| } | |
| /** called by native */ | |
| static void invokePictureCapturedCallback(long picturePtr, PictureCapturedCallback callback) { | |
| Picture picture = new Picture(picturePtr); | |
| callback.onPictureCaptured(picture); | |
| } | |
| /** | |
| * Interface used to receive callbacks when Webview requests a surface control. | |
| * | |
| * @hide | |
| */ | |
| public interface PrepareSurfaceControlForWebviewCallback { | |
| /** | |
| * Invoked when Webview calls to get a surface control. | |
| * | |
| */ | |
| void prepare(); | |
| } | |
| /** | |
| * Interface used to receive callbacks when a transaction needs to be merged. | |
| * | |
| * @hide | |
| */ | |
| public interface ASurfaceTransactionCallback { | |
| /** | |
| * Invoked during a frame drawing. | |
| * | |
| * @param aSurfaceTranactionNativeObj the ASurfaceTransaction native object handle | |
| * @param aSurfaceControlNativeObj ASurfaceControl native object handle | |
| * @param frame The id of the frame being drawn. | |
| */ | |
| boolean onMergeTransaction(long aSurfaceTranactionNativeObj, | |
| long aSurfaceControlNativeObj, long frame); | |
| } | |
| /** | |
| * 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); | |
| /** | |
| * Invoked during a frame drawing. | |
| * | |
| * @param syncResult The result of the draw. Should be a value or a combination of values | |
| * from {@link SyncAndDrawResult} | |
| * @param frame The id of the frame being drawn. | |
| * | |
| * @return A {@link FrameCommitCallback} that will report back if the current vsync draws. | |
| */ | |
| default FrameCommitCallback onFrameDraw(@SyncAndDrawResult int syncResult, long frame) { | |
| onFrameDraw(frame); | |
| return null; | |
| } | |
| } | |
| /** | |
| * Interface used to be notified when a frame has finished rendering | |
| * | |
| * @hide | |
| */ | |
| public interface FrameCommitCallback { | |
| /** | |
| * Invoked after a new frame was drawn | |
| * | |
| * @param didProduceBuffer The draw successfully produced a new buffer. | |
| */ | |
| void onFrameCommit(boolean didProduceBuffer); | |
| } | |
| /** | |
| * Interface used to be notified when RenderThread has finished an attempt to draw. This doesn't | |
| * mean a new frame has drawn, specifically if there's nothing new to draw, but only that | |
| * RenderThread had a chance to draw a frame. | |
| * | |
| * @hide | |
| */ | |
| public interface FrameCompleteCallback { | |
| /** | |
| * Invoked after a frame draw was attempted. | |
| */ | |
| void onFrameComplete(); | |
| } | |
| /** | |
| * Interface for listening to picture captures | |
| * @hide | |
| */ | |
| public interface PictureCapturedCallback { | |
| /** @hide */ | |
| void onPictureCaptured(Picture picture); | |
| } | |
| 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); | |
| } | |
| } | |
| /** | |
| * Notifies the hardware renderer about pending choreographer callbacks. | |
| * | |
| * @hide | |
| */ | |
| public void notifyCallbackPending() { | |
| nNotifyCallbackPending(mNativeProxy); | |
| } | |
| /** | |
| * Notifies the hardware renderer about upcoming expensive frames. | |
| * | |
| * @hide | |
| */ | |
| public void notifyExpensiveFrame() { | |
| nNotifyExpensiveFrame(mNativeProxy); | |
| } | |
| /** | |
| * b/68769804, b/66945974: For low FPS experiments. | |
| * | |
| * @hide | |
| */ | |
| public static void setFPSDivisor(int divisor) { | |
| nSetRtAnimationsEnabled(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); | |
| ProcessInitializer.sInstance.setIsolated(isIsolated); | |
| } | |
| /** | |
| * Sends device configuration changes to the render thread, for rendering profiling views. | |
| * | |
| * @hide | |
| */ | |
| public static void sendDeviceConfigurationForDebugging(Configuration config) { | |
| if (config.densityDpi != Configuration.DENSITY_DPI_UNDEFINED | |
| && config.densityDpi != sDensityDpi) { | |
| sDensityDpi = config.densityDpi; | |
| nSetDisplayDensityDpi(config.densityDpi); | |
| } | |
| } | |
| /** | |
| * If set extra graphics debugging abilities will be enabled such as dumping skp | |
| * | |
| * @hide | |
| */ | |
| public static void setDebuggingEnabled(boolean enable) { | |
| nSetDebuggingEnabled(enable); | |
| } | |
| /** @hide */ | |
| public abstract static class CopyRequest { | |
| protected Bitmap mDestinationBitmap; | |
| final Rect mSrcRect; | |
| protected CopyRequest(Rect srcRect, Bitmap destinationBitmap) { | |
| mDestinationBitmap = destinationBitmap; | |
| if (srcRect != null) { | |
| mSrcRect = srcRect; | |
| } else { | |
| mSrcRect = new Rect(); | |
| } | |
| } | |
| /** | |
| * Retrieve the bitmap in which to store the result of the copy request | |
| */ | |
| public long getDestinationBitmap(int srcWidth, int srcHeight) { | |
| if (mDestinationBitmap == null) { | |
| mDestinationBitmap = | |
| Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); | |
| } | |
| return mDestinationBitmap.getNativeInstance(); | |
| } | |
| /** Called when the copy is completed */ | |
| public abstract void onCopyFinished(int result); | |
| } | |
| /** @hide */ | |
| public static void copySurfaceInto(Surface surface, CopyRequest copyRequest) { | |
| final Rect srcRect = copyRequest.mSrcRect; | |
| nCopySurfaceInto(surface, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, | |
| copyRequest); | |
| } | |
| /** | |
| * 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); | |
| } | |
| /** | |
| * Invoke this when all font caches should be flushed. This can cause jank on next render | |
| * commands so use it only after expensive font allocation operations which would | |
| * allocate large amount of temporary memory. | |
| * | |
| * @param level Hint about which caches to trim. See {@link #CACHE_TRIM_ALL}, | |
| * {@link #CACHE_TRIM_FONT}, {@link #CACHE_TRIM_RESOURCES} | |
| * | |
| * @hide | |
| */ | |
| public static void trimCaches(@CacheTrimLevel int level) { | |
| nTrimCaches(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); | |
| } | |
| /** | |
| * Gets a context for process initialization | |
| * | |
| * TODO: Remove this once there is a static method for retrieving an application's context. | |
| * | |
| * @hide | |
| */ | |
| public static void setContextForInit(Context context) { | |
| ProcessInitializer.sInstance.setContext(context); | |
| } | |
| /** | |
| * Sets whether or not the current process is a system or persistent process. Used to influence | |
| * the chosen memory usage policy. | |
| * | |
| * @hide | |
| **/ | |
| public static void setIsSystemOrPersistent() { | |
| nSetIsSystemOrPersistent(true); | |
| } | |
| /** | |
| * Returns true if HardwareRender will produce output. | |
| * | |
| * This value is global to the process and affects all uses of HardwareRenderer, | |
| * including | |
| * those created by the system such as those used by the View tree when using hardware | |
| * accelerated rendering. | |
| * | |
| * Default is true in all production environments, but may be false in testing-focused | |
| * emulators or if {@link #setDrawingEnabled(boolean)} is used. | |
| */ | |
| public static boolean isDrawingEnabled() { | |
| return nIsDrawingEnabled(); | |
| } | |
| /** | |
| * Toggles whether or not HardwareRenderer will produce drawing output globally in the current | |
| * process. | |
| * | |
| * This applies to all HardwareRenderer instances, including those created by the platform such | |
| * as those used by the system for hardware accelerated View rendering. | |
| * | |
| * The capability to disable drawing output is intended for test environments, primarily | |
| * headless ones. By setting this to false, tests that launch activities or interact with Views | |
| * can be quicker with less RAM usage by skipping the final step of View drawing. All View | |
| * lifecycle events will occur as normal, only the final step of rendering on the GPU to the | |
| * display will be skipped. | |
| * | |
| * This can be toggled on and off at will, so screenshot tests can also run in this same | |
| * environment by toggling drawing back on and forcing a frame to be drawn such as by calling | |
| * view#invalidate(). Once drawn and the screenshot captured, this can then be turned back off. | |
| */ | |
| // TODO(b/194195794): Add link to androidx's Screenshot library for help with this | |
| public static void setDrawingEnabled(boolean drawingEnabled) { | |
| nSetDrawingEnabled(drawingEnabled); | |
| } | |
| /** | |
| * Disable RenderThread animations that schedule draws directly from RenderThread. This is used | |
| * when we don't want to de-schedule draw requests that come from the UI thread. | |
| * | |
| * @hide | |
| */ | |
| public static void setRtAnimationsEnabled(boolean enabled) { | |
| nSetRtAnimationsEnabled(enabled); | |
| } | |
| 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 boolean mDisplayInitialized = false; | |
| private boolean mIsolated = false; | |
| private Context mContext; | |
| 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 setIsolated(boolean isolated) { | |
| if (mInitialized) return; | |
| mIsolated = isolated; | |
| } | |
| synchronized void setContext(Context context) { | |
| if (mInitialized) return; | |
| mContext = context; | |
| } | |
| 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); | |
| } | |
| } | |
| synchronized void initUsingContext() { | |
| if (mContext == null) return; | |
| initDisplayInfo(); | |
| nSetIsHighEndGfx(ActivityManager.isHighEndGfx()); | |
| nSetIsLowRam(ActivityManager.isLowRamDeviceStatic()); | |
| // Defensively clear out the context in case we were passed a context that can leak | |
| // if we live longer than it, e.g. an activity context. | |
| mContext = null; | |
| } | |
| private void initDisplayInfo() { | |
| if (mDisplayInitialized) return; | |
| if (mIsolated) { | |
| mDisplayInitialized = true; | |
| return; | |
| } | |
| DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); | |
| if (dm == null) { | |
| Log.d(LOG_TAG, "Failed to find DisplayManager for display-based configuration"); | |
| return; | |
| } | |
| final Display defaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY); | |
| if (defaultDisplay == null) { | |
| Log.d(LOG_TAG, "Failed to find default display for display-based configuration"); | |
| return; | |
| } | |
| final Display[] allDisplays = dm.getDisplays(); | |
| if (allDisplays.length == 0) { | |
| Log.d(LOG_TAG, "Failed to query displays"); | |
| return; | |
| } | |
| final Mode activeMode = defaultDisplay.getMode(); | |
| final ColorSpace defaultWideColorSpace = | |
| defaultDisplay.getPreferredWideGamutColorSpace(); | |
| int wideColorDataspace = defaultWideColorSpace != null | |
| ? defaultWideColorSpace.getDataSpace() : 0; | |
| // largest width & height are used to size the default HWUI cache sizes. So find the | |
| // largest display resolution we could encounter & use that as the guidance. The actual | |
| // memory policy in play will interpret these values differently. | |
| int largestWidth = activeMode.getPhysicalWidth(); | |
| int largestHeight = activeMode.getPhysicalHeight(); | |
| final OverlayProperties overlayProperties = defaultDisplay.getOverlaySupport(); | |
| for (int i = 0; i < allDisplays.length; i++) { | |
| final Display display = allDisplays[i]; | |
| // Take the first wide gamut dataspace as the source of truth | |
| // Possibly should do per-HardwareRenderer wide gamut dataspace so we can use the | |
| // target display's ideal instead | |
| if (wideColorDataspace == 0) { | |
| ColorSpace cs = display.getPreferredWideGamutColorSpace(); | |
| if (cs != null) { | |
| wideColorDataspace = cs.getDataSpace(); | |
| } | |
| } | |
| Mode[] modes = display.getSupportedModes(); | |
| for (int j = 0; j < modes.length; j++) { | |
| Mode mode = modes[j]; | |
| int width = mode.getPhysicalWidth(); | |
| int height = mode.getPhysicalHeight(); | |
| if ((width * height) > (largestWidth * largestHeight)) { | |
| largestWidth = width; | |
| largestHeight = height; | |
| } | |
| } | |
| } | |
| nInitDisplayInfo(largestWidth, largestHeight, defaultDisplay.getRefreshRate(), | |
| wideColorDataspace, defaultDisplay.getAppVsyncOffsetNanos(), | |
| defaultDisplay.getPresentationDeadlineNanos(), | |
| overlayProperties.isCombinationSupported( | |
| DataSpace.DATASPACE_SCRGB, HardwareBuffer.RGBA_FP16), | |
| overlayProperties.isCombinationSupported( | |
| DataSpace.pack( | |
| DataSpace.STANDARD_DCI_P3, | |
| DataSpace.TRANSFER_SRGB, | |
| DataSpace.RANGE_EXTENDED), | |
| HardwareBuffer.RGBA_10101010), | |
| overlayProperties.isMixedColorSpacesSupported()); | |
| mDisplayInitialized = true; | |
| } | |
| 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(); | |
| /** | |
| * Start render thread and initialize EGL or Vulkan. | |
| * | |
| * Initializing EGL involves loading and initializing the graphics driver. Some drivers take | |
| * several 10s of milliseconds to do this, so doing it on-demand when an app tries to render | |
| * its first frame adds directly to user-visible app launch latency. | |
| * | |
| * Should only be called after GraphicsEnvironment.chooseDriver(). | |
| * @hide | |
| */ | |
| public static native void preload(); | |
| /** | |
| * @hide | |
| */ | |
| protected static native boolean isWebViewOverlaysEnabled(); | |
| /** @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, boolean discardBuffer); | |
| private static native void nSetSurfaceControl(long nativeProxy, long nativeSurfaceControl); | |
| 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 float nSetColorMode(long nativeProxy, int colorMode); | |
| private static native void nSetTargetSdrHdrRatio(long nativeProxy, float ratio); | |
| private static native void nSetSdrWhitePoint(long nativeProxy, float whitePoint); | |
| private static native void nSetIsHighEndGfx(boolean isHighEndGfx); | |
| private static native void nSetIsLowRam(boolean isLowRam); | |
| private static native void nSetIsSystemOrPersistent(boolean isSystemOrPersistent); | |
| 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 long nCreateTextureLayer(long nativeProxy); | |
| private static native void nBuildLayer(long nativeProxy, long node); | |
| private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmapHandle); | |
| 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 nTrimCaches(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 nDumpGlobalProfileInfo(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 nForceDrawNextFrame(long nativeProxy); | |
| private static native void nSetPictureCaptureCallback(long nativeProxy, | |
| PictureCapturedCallback callback); | |
| private static native void nSetASurfaceTransactionCallback(long nativeProxy, | |
| ASurfaceTransactionCallback callback); | |
| private static native void nSetPrepareSurfaceControlForWebviewCallback(long nativeProxy, | |
| PrepareSurfaceControlForWebviewCallback callback); | |
| private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback); | |
| private static native void nSetFrameCommitCallback(long nativeProxy, | |
| FrameCommitCallback callback); | |
| private static native void nSetFrameCompleteCallback(long nativeProxy, | |
| FrameCompleteCallback callback); | |
| private static native void nAddObserver(long nativeProxy, long nativeObserver); | |
| private static native void nRemoveObserver(long nativeProxy, long nativeObserver); | |
| private static native void nCopySurfaceInto(Surface surface, | |
| int srcLeft, int srcTop, int srcRight, int srcBottom, CopyRequest request); | |
| private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height); | |
| private static native void nSetHighContrastText(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, int type); | |
| private static native void nSetDisplayDensityDpi(int densityDpi); | |
| private static native void nInitDisplayInfo(int width, int height, float refreshRate, | |
| int wideColorDataspace, long appVsyncOffsetNanos, long presentationDeadlineNanos, | |
| boolean supportsFp16ForHdr, boolean isRgba10101010SupportedForHdr, | |
| boolean nSupportMixedColorSpaces); | |
| private static native void nSetDrawingEnabled(boolean drawingEnabled); | |
| private static native boolean nIsDrawingEnabled(); | |
| private static native void nSetRtAnimationsEnabled(boolean rtAnimationsEnabled); | |
| private static native void nNotifyCallbackPending(long nativeProxy); | |
| private static native void nNotifyExpensiveFrame(long nativeProxy); | |
| } |