All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.graphics.HardwareRenderer Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * 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.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.Optional;
import java.util.concurrent.Executor;
import java.util.stream.Stream;

import sun.misc.Cleaner;

/**
 * 

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.

* *

Resources & lifecycle

* *

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.

* *

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.

*/ 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 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. * *

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 { } /** * 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 boolean mForceDark = false; private @ActivityInfo.ColorMode int mColorMode = ActivityInfo.COLOR_MODE_DEFAULT; /** * 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. * *

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}. * *

It is recommended 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 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. * *

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 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(); } /** *

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).

* *

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.

* * @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) { 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. * *

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. * *

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. * *

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 * @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. * *

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. * *

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. * *

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(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. * * 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. * *

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 void setColorMode(@ActivityInfo.ColorMode int colorMode) { if (mColorMode != colorMode) { mColorMode = colorMode; nSetColorMode(mNativeProxy, colorMode); } } /** * 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); } /** * 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); } } /** * 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 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.getNativeInstance()); } else { return nCopySurfaceInto(surface, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, bitmap.getNativeInstance()); } } /** * 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); } /** * 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); } /** * 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(); // Magic values from android/data_space.h private static final int INTERNAL_DATASPACE_SRGB = 142671872; private static final int INTERNAL_DATASPACE_DISPLAY_P3 = 143261696; private static final int INTERNAL_DATASPACE_SCRGB = 411107328; private enum Dataspace { DISPLAY_P3(ColorSpace.Named.DISPLAY_P3, INTERNAL_DATASPACE_DISPLAY_P3), SCRGB(ColorSpace.Named.EXTENDED_SRGB, INTERNAL_DATASPACE_SCRGB), SRGB(ColorSpace.Named.SRGB, INTERNAL_DATASPACE_SRGB); private final ColorSpace.Named mColorSpace; private final int mNativeDataspace; Dataspace(ColorSpace.Named colorSpace, int nativeDataspace) { this.mColorSpace = colorSpace; this.mNativeDataspace = nativeDataspace; } static Optional find(ColorSpace colorSpace) { return Stream.of(Dataspace.values()) .filter(d -> ColorSpace.get(d.mColorSpace).equals(colorSpace)) .findFirst(); } } 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()); // 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; } Display display = dm.getDisplay(Display.DEFAULT_DISPLAY); if (display == null) { Log.d(LOG_TAG, "Failed to find default display for display-based configuration"); return; } Dataspace wideColorDataspace = Optional.ofNullable(display.getPreferredWideGamutColorSpace()) .flatMap(Dataspace::find) // Default to SRGB if the display doesn't support wide color .orElse(Dataspace.SRGB); // Grab the physical screen dimensions from the active display mode // Strictly speaking the screen resolution may not always be constant - it is for // sizing the font cache for the underlying rendering thread. Since it's a // heuristic we don't need to be always 100% correct. Mode activeMode = display.getMode(); nInitDisplayInfo(activeMode.getPhysicalWidth(), activeMode.getPhysicalHeight(), display.getRefreshRate(), wideColorDataspace.mNativeDataspace, display.getAppVsyncOffsetNanos(), display.getPresentationDeadlineNanos()); 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 void nSetColorMode(long nativeProxy, int colorMode); private static native void nSetSdrWhitePoint(long nativeProxy, float whitePoint); private static native void nSetIsHighEndGfx(boolean isHighEndGfx); 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 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 int nCopySurfaceInto(Surface surface, int srcLeft, int srcTop, int srcRight, int srcBottom, long bitmapHandle); 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, boolean enabled); private static native void nSetDisplayDensityDpi(int densityDpi); private static native void nInitDisplayInfo(int width, int height, float refreshRate, int wideColorDataspace, long appVsyncOffsetNanos, long presentationDeadlineNanos); private static native void nSetDrawingEnabled(boolean drawingEnabled); private static native boolean nIsDrawingEnabled(); private static native void nSetRtAnimationsEnabled(boolean rtAnimationsEnabled); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy