Add back render-ahead support
Currently only supported in the EGL path. Vulkan support Coming Soon Bug: 127822449 Test: trace of hwuimacro Change-Id: Iac2b039e11d964aab5b8ca1bdf2a5430b187e2ea
This commit is contained in:
@@ -7,3 +7,10 @@ prop {
|
||||
scope: Public
|
||||
access: Readonly
|
||||
}
|
||||
prop {
|
||||
api_name: "render_ahead"
|
||||
type: Integer
|
||||
prop_name: "ro.hwui.render_ahead"
|
||||
scope: Public
|
||||
access: Readonly
|
||||
}
|
||||
@@ -67,6 +67,7 @@ bool Properties::debuggingEnabled = false;
|
||||
bool Properties::isolatedProcess = false;
|
||||
|
||||
int Properties::contextPriority = 0;
|
||||
int Properties::defaultRenderAhead = 0;
|
||||
|
||||
static int property_get_int(const char* key, int defaultValue) {
|
||||
char buf[PROPERTY_VALUE_MAX] = {
|
||||
@@ -129,6 +130,13 @@ bool Properties::load() {
|
||||
|
||||
enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, true);
|
||||
|
||||
defaultRenderAhead = std::max(0, std::min(2, property_get_int(PROPERTY_RENDERAHEAD,
|
||||
render_ahead().value_or(0))));
|
||||
|
||||
if (defaultRenderAhead && sRenderPipelineType == RenderPipelineType::SkiaVulkan) {
|
||||
ALOGW("hwui.render_ahead of %d ignored because pipeline is skiavk", defaultRenderAhead);
|
||||
}
|
||||
|
||||
return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw);
|
||||
}
|
||||
|
||||
|
||||
@@ -167,6 +167,8 @@ enum DebugLevel {
|
||||
|
||||
#define PROPERTY_ENABLE_FORCE_DARK "debug.hwui.force_dark_enabled"
|
||||
|
||||
#define PROPERTY_RENDERAHEAD "debug.hwui.render_ahead"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -251,6 +253,8 @@ public:
|
||||
|
||||
ANDROID_API static int contextPriority;
|
||||
|
||||
static int defaultRenderAhead;
|
||||
|
||||
private:
|
||||
static ProfileType sProfileType;
|
||||
static bool sDisableProfileBars;
|
||||
|
||||
@@ -111,6 +111,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode*
|
||||
rootRenderNode->makeRoot();
|
||||
mRenderNodes.emplace_back(rootRenderNode);
|
||||
mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
|
||||
setRenderAheadDepth(Properties::defaultRenderAhead);
|
||||
}
|
||||
|
||||
CanvasContext::~CanvasContext() {
|
||||
@@ -159,6 +160,7 @@ void CanvasContext::setSurface(sp<Surface>&& surface) {
|
||||
if (hasSurface) {
|
||||
mHaveNewSurface = true;
|
||||
mSwapHistory.clear();
|
||||
applyRenderAheadSettings();
|
||||
} else {
|
||||
mRenderThread.removeFrameCallback(this);
|
||||
mGenerationID++;
|
||||
@@ -423,6 +425,12 @@ void CanvasContext::draw() {
|
||||
|
||||
waitOnFences();
|
||||
|
||||
if (mRenderAheadDepth) {
|
||||
auto presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
|
||||
(mRenderThread.timeLord().frameIntervalNanos() * (mRenderAheadDepth + 1));
|
||||
native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
|
||||
}
|
||||
|
||||
bool requireSwap = false;
|
||||
bool didSwap =
|
||||
mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);
|
||||
@@ -636,6 +644,28 @@ bool CanvasContext::surfaceRequiresRedraw() {
|
||||
return width == mLastFrameWidth && height == mLastFrameHeight;
|
||||
}
|
||||
|
||||
void CanvasContext::applyRenderAheadSettings() {
|
||||
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
|
||||
// TODO: Fix SkiaVulkan's assumptions on buffer counts. And SIGBUS crashes.
|
||||
mRenderAheadDepth = 0;
|
||||
return;
|
||||
}
|
||||
if (mNativeSurface) {
|
||||
native_window_set_buffer_count(mNativeSurface.get(), 3 + mRenderAheadDepth);
|
||||
if (!mRenderAheadDepth) {
|
||||
native_window_set_buffers_timestamp(mNativeSurface.get(), NATIVE_WINDOW_TIMESTAMP_AUTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasContext::setRenderAheadDepth(int renderAhead) {
|
||||
if (renderAhead < 0 || renderAhead > 2 || renderAhead == mRenderAheadDepth) {
|
||||
return;
|
||||
}
|
||||
mRenderAheadDepth = renderAhead;
|
||||
applyRenderAheadSettings();
|
||||
}
|
||||
|
||||
SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
|
||||
if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) {
|
||||
// can't rely on prior content of window if viewport size changes
|
||||
|
||||
@@ -204,6 +204,8 @@ public:
|
||||
return mUseForceDark;
|
||||
}
|
||||
|
||||
void setRenderAheadDepth(int renderAhead);
|
||||
|
||||
private:
|
||||
CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
|
||||
IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
|
||||
@@ -217,6 +219,7 @@ private:
|
||||
|
||||
bool isSwapChainStuffed();
|
||||
bool surfaceRequiresRedraw();
|
||||
void applyRenderAheadSettings();
|
||||
|
||||
SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
|
||||
|
||||
@@ -235,6 +238,7 @@ private:
|
||||
// painted onto its surface.
|
||||
bool mIsDirty = false;
|
||||
SwapBehavior mSwapBehavior = SwapBehavior::kSwap_default;
|
||||
int mRenderAheadDepth = 0;
|
||||
struct SwapHistory {
|
||||
SkRect damage;
|
||||
nsecs_t vsyncTime;
|
||||
|
||||
@@ -312,6 +312,12 @@ void RenderProxy::setForceDark(bool enable) {
|
||||
mRenderThread.queue().post([this, enable]() { mContext->setForceDark(enable); });
|
||||
}
|
||||
|
||||
void RenderProxy::setRenderAheadDepth(int renderAhead) {
|
||||
mRenderThread.queue().post([ context = mContext, renderAhead ] {
|
||||
context->setRenderAheadDepth(renderAhead);
|
||||
});
|
||||
}
|
||||
|
||||
int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
|
||||
SkBitmap* bitmap) {
|
||||
auto& thread = RenderThread::getInstance();
|
||||
|
||||
@@ -123,6 +123,23 @@ public:
|
||||
ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
|
||||
ANDROID_API void setForceDark(bool enable);
|
||||
|
||||
/**
|
||||
* Sets a render-ahead depth on the backing renderer. This will increase latency by
|
||||
* <swapInterval> * renderAhead and increase memory usage by (3 + renderAhead) * <resolution>.
|
||||
* In return the renderer will be less susceptible to jitter, resulting in a smoother animation.
|
||||
*
|
||||
* Not recommended to use in response to anything touch driven, but for canned animations
|
||||
* where latency is not a concern careful use may be beneficial.
|
||||
*
|
||||
* Note that when increasing this there will be a frame gap of N frames where N is
|
||||
* renderAhead - <current renderAhead>. When decreasing this if there are any pending
|
||||
* frames they will retain their prior renderAhead value, so it will take a few frames
|
||||
* for the decrease to flush through.
|
||||
*
|
||||
* @param renderAhead How far to render ahead, must be in the range [0..2]
|
||||
*/
|
||||
ANDROID_API void setRenderAheadDepth(int renderAhead);
|
||||
|
||||
ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right,
|
||||
int bottom, SkBitmap* bitmap);
|
||||
ANDROID_API static void prepareToDraw(Bitmap& bitmap);
|
||||
|
||||
@@ -38,6 +38,7 @@ public:
|
||||
int count = 0;
|
||||
int reportFrametimeWeight = 0;
|
||||
bool renderOffscreen = true;
|
||||
int renderAhead = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
||||
@@ -154,6 +154,11 @@ void run(const TestScene::Info& info, const TestScene::Options& opts,
|
||||
proxy->resetProfileInfo();
|
||||
proxy->fence();
|
||||
|
||||
if (opts.renderAhead) {
|
||||
usleep(33000);
|
||||
}
|
||||
proxy->setRenderAheadDepth(opts.renderAhead);
|
||||
|
||||
ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight);
|
||||
|
||||
nsecs_t start = systemTime(CLOCK_MONOTONIC);
|
||||
|
||||
@@ -69,6 +69,7 @@ OPTIONS:
|
||||
are offscreen rendered
|
||||
--benchmark_format Set output format. Possible values are tabular, json, csv
|
||||
--renderer=TYPE Sets the render pipeline to use. May be skiagl or skiavk
|
||||
--render-ahead=NUM Sets how far to render-ahead. Must be 0 (default), 1, or 2.
|
||||
)");
|
||||
}
|
||||
|
||||
@@ -170,6 +171,7 @@ enum {
|
||||
Onscreen,
|
||||
Offscreen,
|
||||
Renderer,
|
||||
RenderAhead,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -185,6 +187,7 @@ static const struct option LONG_OPTIONS[] = {
|
||||
{"onscreen", no_argument, nullptr, LongOpts::Onscreen},
|
||||
{"offscreen", no_argument, nullptr, LongOpts::Offscreen},
|
||||
{"renderer", required_argument, nullptr, LongOpts::Renderer},
|
||||
{"render-ahead", required_argument, nullptr, LongOpts::RenderAhead},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
static const char* SHORT_OPTIONS = "c:r:h";
|
||||
@@ -283,6 +286,16 @@ void parseOptions(int argc, char* argv[]) {
|
||||
gOpts.renderOffscreen = true;
|
||||
break;
|
||||
|
||||
case LongOpts::RenderAhead:
|
||||
if (!optarg) {
|
||||
error = true;
|
||||
}
|
||||
gOpts.renderAhead = atoi(optarg);
|
||||
if (gOpts.renderAhead < 0 || gOpts.renderAhead > 2) {
|
||||
error = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
printHelp();
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
Reference in New Issue
Block a user