1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2013 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker *
4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker *
8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker *
10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker */
16*d57664e9SAndroid Build Coastguard Worker
17*d57664e9SAndroid Build Coastguard Worker #include "RenderThread.h"
18*d57664e9SAndroid Build Coastguard Worker
19*d57664e9SAndroid Build Coastguard Worker #include <android-base/properties.h>
20*d57664e9SAndroid Build Coastguard Worker #include <dlfcn.h>
21*d57664e9SAndroid Build Coastguard Worker #include <gui/TraceUtils.h>
22*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/GrContextOptions.h>
23*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/gl/GrGLDirectContext.h>
24*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/gl/GrGLInterface.h>
25*d57664e9SAndroid Build Coastguard Worker #include <private/android/choreographer.h>
26*d57664e9SAndroid Build Coastguard Worker #include <sys/resource.h>
27*d57664e9SAndroid Build Coastguard Worker #include <ui/FatVector.h>
28*d57664e9SAndroid Build Coastguard Worker #include <utils/Condition.h>
29*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
30*d57664e9SAndroid Build Coastguard Worker #include <utils/Mutex.h>
31*d57664e9SAndroid Build Coastguard Worker
32*d57664e9SAndroid Build Coastguard Worker #include <thread>
33*d57664e9SAndroid Build Coastguard Worker
34*d57664e9SAndroid Build Coastguard Worker #include "../HardwareBitmapUploader.h"
35*d57664e9SAndroid Build Coastguard Worker #include "CacheManager.h"
36*d57664e9SAndroid Build Coastguard Worker #include "CanvasContext.h"
37*d57664e9SAndroid Build Coastguard Worker #include "DeviceInfo.h"
38*d57664e9SAndroid Build Coastguard Worker #include "EglManager.h"
39*d57664e9SAndroid Build Coastguard Worker #include "Properties.h"
40*d57664e9SAndroid Build Coastguard Worker #include "Readback.h"
41*d57664e9SAndroid Build Coastguard Worker #include "RenderProxy.h"
42*d57664e9SAndroid Build Coastguard Worker #include "VulkanManager.h"
43*d57664e9SAndroid Build Coastguard Worker #include "hwui/Bitmap.h"
44*d57664e9SAndroid Build Coastguard Worker #include "pipeline/skia/SkiaOpenGLPipeline.h"
45*d57664e9SAndroid Build Coastguard Worker #include "pipeline/skia/SkiaVulkanPipeline.h"
46*d57664e9SAndroid Build Coastguard Worker #include "renderstate/RenderState.h"
47*d57664e9SAndroid Build Coastguard Worker #include "utils/TimeUtils.h"
48*d57664e9SAndroid Build Coastguard Worker
49*d57664e9SAndroid Build Coastguard Worker namespace android {
50*d57664e9SAndroid Build Coastguard Worker namespace uirenderer {
51*d57664e9SAndroid Build Coastguard Worker namespace renderthread {
52*d57664e9SAndroid Build Coastguard Worker
53*d57664e9SAndroid Build Coastguard Worker static bool gHasRenderThreadInstance = false;
54*d57664e9SAndroid Build Coastguard Worker
55*d57664e9SAndroid Build Coastguard Worker static JVMAttachHook gOnStartHook = nullptr;
56*d57664e9SAndroid Build Coastguard Worker
ASurfaceControlFunctions()57*d57664e9SAndroid Build Coastguard Worker ASurfaceControlFunctions::ASurfaceControlFunctions() {
58*d57664e9SAndroid Build Coastguard Worker void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
59*d57664e9SAndroid Build Coastguard Worker createFunc = (ASC_create)dlsym(handle_, "ASurfaceControl_create");
60*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(createFunc == nullptr,
61*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceControl_create!");
62*d57664e9SAndroid Build Coastguard Worker
63*d57664e9SAndroid Build Coastguard Worker acquireFunc = (ASC_acquire) dlsym(handle_, "ASurfaceControl_acquire");
64*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(acquireFunc == nullptr,
65*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceControl_acquire!");
66*d57664e9SAndroid Build Coastguard Worker
67*d57664e9SAndroid Build Coastguard Worker releaseFunc = (ASC_release) dlsym(handle_, "ASurfaceControl_release");
68*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(releaseFunc == nullptr,
69*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceControl_release!");
70*d57664e9SAndroid Build Coastguard Worker
71*d57664e9SAndroid Build Coastguard Worker registerListenerFunc = (ASC_registerSurfaceStatsListener) dlsym(handle_,
72*d57664e9SAndroid Build Coastguard Worker "ASurfaceControl_registerSurfaceStatsListener");
73*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(registerListenerFunc == nullptr,
74*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceControl_registerSurfaceStatsListener!");
75*d57664e9SAndroid Build Coastguard Worker
76*d57664e9SAndroid Build Coastguard Worker unregisterListenerFunc = (ASC_unregisterSurfaceStatsListener) dlsym(handle_,
77*d57664e9SAndroid Build Coastguard Worker "ASurfaceControl_unregisterSurfaceStatsListener");
78*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(unregisterListenerFunc == nullptr,
79*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceControl_unregisterSurfaceStatsListener!");
80*d57664e9SAndroid Build Coastguard Worker
81*d57664e9SAndroid Build Coastguard Worker getAcquireTimeFunc = (ASCStats_getAcquireTime) dlsym(handle_,
82*d57664e9SAndroid Build Coastguard Worker "ASurfaceControlStats_getAcquireTime");
83*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(getAcquireTimeFunc == nullptr,
84*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceControlStats_getAcquireTime!");
85*d57664e9SAndroid Build Coastguard Worker
86*d57664e9SAndroid Build Coastguard Worker getFrameNumberFunc = (ASCStats_getFrameNumber) dlsym(handle_,
87*d57664e9SAndroid Build Coastguard Worker "ASurfaceControlStats_getFrameNumber");
88*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(getFrameNumberFunc == nullptr,
89*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceControlStats_getFrameNumber!");
90*d57664e9SAndroid Build Coastguard Worker
91*d57664e9SAndroid Build Coastguard Worker transactionCreateFunc = (AST_create)dlsym(handle_, "ASurfaceTransaction_create");
92*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(transactionCreateFunc == nullptr,
93*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceTransaction_create!");
94*d57664e9SAndroid Build Coastguard Worker
95*d57664e9SAndroid Build Coastguard Worker transactionDeleteFunc = (AST_delete)dlsym(handle_, "ASurfaceTransaction_delete");
96*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(transactionDeleteFunc == nullptr,
97*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceTransaction_delete!");
98*d57664e9SAndroid Build Coastguard Worker
99*d57664e9SAndroid Build Coastguard Worker transactionApplyFunc = (AST_apply)dlsym(handle_, "ASurfaceTransaction_apply");
100*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(transactionApplyFunc == nullptr,
101*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceTransaction_apply!");
102*d57664e9SAndroid Build Coastguard Worker
103*d57664e9SAndroid Build Coastguard Worker transactionReparentFunc = (AST_reparent)dlsym(handle_, "ASurfaceTransaction_reparent");
104*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(transactionReparentFunc == nullptr,
105*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol transactionReparentFunc!");
106*d57664e9SAndroid Build Coastguard Worker
107*d57664e9SAndroid Build Coastguard Worker transactionSetVisibilityFunc =
108*d57664e9SAndroid Build Coastguard Worker (AST_setVisibility)dlsym(handle_, "ASurfaceTransaction_setVisibility");
109*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(transactionSetVisibilityFunc == nullptr,
110*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceTransaction_setVisibility!");
111*d57664e9SAndroid Build Coastguard Worker
112*d57664e9SAndroid Build Coastguard Worker transactionSetZOrderFunc = (AST_setZOrder)dlsym(handle_, "ASurfaceTransaction_setZOrder");
113*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(transactionSetZOrderFunc == nullptr,
114*d57664e9SAndroid Build Coastguard Worker "Failed to find required symbol ASurfaceTransaction_setZOrder!");
115*d57664e9SAndroid Build Coastguard Worker }
116*d57664e9SAndroid Build Coastguard Worker
extendedFrameCallback(const AChoreographerFrameCallbackData * cbData,void * data)117*d57664e9SAndroid Build Coastguard Worker void RenderThread::extendedFrameCallback(const AChoreographerFrameCallbackData* cbData,
118*d57664e9SAndroid Build Coastguard Worker void* data) {
119*d57664e9SAndroid Build Coastguard Worker RenderThread* rt = reinterpret_cast<RenderThread*>(data);
120*d57664e9SAndroid Build Coastguard Worker size_t preferredFrameTimelineIndex =
121*d57664e9SAndroid Build Coastguard Worker AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(cbData);
122*d57664e9SAndroid Build Coastguard Worker AVsyncId vsyncId = AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
123*d57664e9SAndroid Build Coastguard Worker cbData, preferredFrameTimelineIndex);
124*d57664e9SAndroid Build Coastguard Worker int64_t frameDeadline = AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
125*d57664e9SAndroid Build Coastguard Worker cbData, preferredFrameTimelineIndex);
126*d57664e9SAndroid Build Coastguard Worker int64_t frameTimeNanos = AChoreographerFrameCallbackData_getFrameTimeNanos(cbData);
127*d57664e9SAndroid Build Coastguard Worker // TODO(b/193273294): Remove when shared memory in use w/ expected present time always current.
128*d57664e9SAndroid Build Coastguard Worker int64_t frameInterval = AChoreographer_getFrameInterval(rt->mChoreographer);
129*d57664e9SAndroid Build Coastguard Worker rt->frameCallback(vsyncId, frameDeadline, frameTimeNanos, frameInterval);
130*d57664e9SAndroid Build Coastguard Worker }
131*d57664e9SAndroid Build Coastguard Worker
frameCallback(int64_t vsyncId,int64_t frameDeadline,int64_t frameTimeNanos,int64_t frameInterval)132*d57664e9SAndroid Build Coastguard Worker void RenderThread::frameCallback(int64_t vsyncId, int64_t frameDeadline, int64_t frameTimeNanos,
133*d57664e9SAndroid Build Coastguard Worker int64_t frameInterval) {
134*d57664e9SAndroid Build Coastguard Worker mVsyncRequested = false;
135*d57664e9SAndroid Build Coastguard Worker if (timeLord().vsyncReceived(frameTimeNanos, frameTimeNanos, vsyncId, frameDeadline,
136*d57664e9SAndroid Build Coastguard Worker frameInterval) &&
137*d57664e9SAndroid Build Coastguard Worker !mFrameCallbackTaskPending) {
138*d57664e9SAndroid Build Coastguard Worker mFrameCallbackTaskPending = true;
139*d57664e9SAndroid Build Coastguard Worker
140*d57664e9SAndroid Build Coastguard Worker using SteadyClock = std::chrono::steady_clock;
141*d57664e9SAndroid Build Coastguard Worker using Nanos = std::chrono::nanoseconds;
142*d57664e9SAndroid Build Coastguard Worker using toNsecs_t = std::chrono::duration<nsecs_t, std::nano>;
143*d57664e9SAndroid Build Coastguard Worker using toFloatMillis = std::chrono::duration<float, std::milli>;
144*d57664e9SAndroid Build Coastguard Worker
145*d57664e9SAndroid Build Coastguard Worker const auto frameTimeTimePoint = SteadyClock::time_point(Nanos(frameTimeNanos));
146*d57664e9SAndroid Build Coastguard Worker const auto deadlineTimePoint = SteadyClock::time_point(Nanos(frameDeadline));
147*d57664e9SAndroid Build Coastguard Worker
148*d57664e9SAndroid Build Coastguard Worker const auto timeUntilDeadline = deadlineTimePoint - frameTimeTimePoint;
149*d57664e9SAndroid Build Coastguard Worker const auto runAt = (frameTimeTimePoint + (timeUntilDeadline / 4));
150*d57664e9SAndroid Build Coastguard Worker
151*d57664e9SAndroid Build Coastguard Worker ATRACE_FORMAT("queue mFrameCallbackTask to run after %.2fms",
152*d57664e9SAndroid Build Coastguard Worker toFloatMillis(runAt - SteadyClock::now()).count());
153*d57664e9SAndroid Build Coastguard Worker queue().postAt(toNsecs_t(runAt.time_since_epoch()).count(),
154*d57664e9SAndroid Build Coastguard Worker [this]() { dispatchFrameCallbacks(); });
155*d57664e9SAndroid Build Coastguard Worker }
156*d57664e9SAndroid Build Coastguard Worker }
157*d57664e9SAndroid Build Coastguard Worker
refreshRateCallback(int64_t vsyncPeriod,void * data)158*d57664e9SAndroid Build Coastguard Worker void RenderThread::refreshRateCallback(int64_t vsyncPeriod, void* data) {
159*d57664e9SAndroid Build Coastguard Worker ATRACE_NAME("refreshRateCallback");
160*d57664e9SAndroid Build Coastguard Worker RenderThread* rt = reinterpret_cast<RenderThread*>(data);
161*d57664e9SAndroid Build Coastguard Worker DeviceInfo::get()->onRefreshRateChanged(vsyncPeriod);
162*d57664e9SAndroid Build Coastguard Worker rt->setupFrameInterval();
163*d57664e9SAndroid Build Coastguard Worker }
164*d57664e9SAndroid Build Coastguard Worker
165*d57664e9SAndroid Build Coastguard Worker class ChoreographerSource : public VsyncSource {
166*d57664e9SAndroid Build Coastguard Worker public:
ChoreographerSource(RenderThread * renderThread)167*d57664e9SAndroid Build Coastguard Worker ChoreographerSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
168*d57664e9SAndroid Build Coastguard Worker
requestNextVsync()169*d57664e9SAndroid Build Coastguard Worker virtual void requestNextVsync() override {
170*d57664e9SAndroid Build Coastguard Worker AChoreographer_postVsyncCallback(mRenderThread->mChoreographer,
171*d57664e9SAndroid Build Coastguard Worker RenderThread::extendedFrameCallback, mRenderThread);
172*d57664e9SAndroid Build Coastguard Worker }
173*d57664e9SAndroid Build Coastguard Worker
drainPendingEvents()174*d57664e9SAndroid Build Coastguard Worker virtual void drainPendingEvents() override {
175*d57664e9SAndroid Build Coastguard Worker AChoreographer_handlePendingEvents(mRenderThread->mChoreographer, mRenderThread);
176*d57664e9SAndroid Build Coastguard Worker }
177*d57664e9SAndroid Build Coastguard Worker
178*d57664e9SAndroid Build Coastguard Worker private:
179*d57664e9SAndroid Build Coastguard Worker RenderThread* mRenderThread;
180*d57664e9SAndroid Build Coastguard Worker };
181*d57664e9SAndroid Build Coastguard Worker
182*d57664e9SAndroid Build Coastguard Worker class DummyVsyncSource : public VsyncSource {
183*d57664e9SAndroid Build Coastguard Worker public:
DummyVsyncSource(RenderThread * renderThread)184*d57664e9SAndroid Build Coastguard Worker DummyVsyncSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
185*d57664e9SAndroid Build Coastguard Worker
requestNextVsync()186*d57664e9SAndroid Build Coastguard Worker virtual void requestNextVsync() override {
187*d57664e9SAndroid Build Coastguard Worker mRenderThread->queue().postDelayed(16_ms, [this]() {
188*d57664e9SAndroid Build Coastguard Worker mRenderThread->frameCallback(UiFrameInfoBuilder::INVALID_VSYNC_ID,
189*d57664e9SAndroid Build Coastguard Worker std::numeric_limits<int64_t>::max(),
190*d57664e9SAndroid Build Coastguard Worker systemTime(SYSTEM_TIME_MONOTONIC), 16_ms);
191*d57664e9SAndroid Build Coastguard Worker });
192*d57664e9SAndroid Build Coastguard Worker }
193*d57664e9SAndroid Build Coastguard Worker
drainPendingEvents()194*d57664e9SAndroid Build Coastguard Worker virtual void drainPendingEvents() override {
195*d57664e9SAndroid Build Coastguard Worker mRenderThread->frameCallback(UiFrameInfoBuilder::INVALID_VSYNC_ID,
196*d57664e9SAndroid Build Coastguard Worker std::numeric_limits<int64_t>::max(),
197*d57664e9SAndroid Build Coastguard Worker systemTime(SYSTEM_TIME_MONOTONIC), 16_ms);
198*d57664e9SAndroid Build Coastguard Worker }
199*d57664e9SAndroid Build Coastguard Worker
200*d57664e9SAndroid Build Coastguard Worker private:
201*d57664e9SAndroid Build Coastguard Worker RenderThread* mRenderThread;
202*d57664e9SAndroid Build Coastguard Worker };
203*d57664e9SAndroid Build Coastguard Worker
hasInstance()204*d57664e9SAndroid Build Coastguard Worker bool RenderThread::hasInstance() {
205*d57664e9SAndroid Build Coastguard Worker return gHasRenderThreadInstance;
206*d57664e9SAndroid Build Coastguard Worker }
207*d57664e9SAndroid Build Coastguard Worker
setOnStartHook(JVMAttachHook onStartHook)208*d57664e9SAndroid Build Coastguard Worker void RenderThread::setOnStartHook(JVMAttachHook onStartHook) {
209*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(hasInstance(), "can't set an onStartHook after we've started...");
210*d57664e9SAndroid Build Coastguard Worker gOnStartHook = onStartHook;
211*d57664e9SAndroid Build Coastguard Worker }
212*d57664e9SAndroid Build Coastguard Worker
getOnStartHook()213*d57664e9SAndroid Build Coastguard Worker JVMAttachHook RenderThread::getOnStartHook() {
214*d57664e9SAndroid Build Coastguard Worker return gOnStartHook;
215*d57664e9SAndroid Build Coastguard Worker }
216*d57664e9SAndroid Build Coastguard Worker
getInstance()217*d57664e9SAndroid Build Coastguard Worker RenderThread& RenderThread::getInstance() {
218*d57664e9SAndroid Build Coastguard Worker [[clang::no_destroy]] static sp<RenderThread> sInstance = []() {
219*d57664e9SAndroid Build Coastguard Worker sp<RenderThread> thread = sp<RenderThread>::make();
220*d57664e9SAndroid Build Coastguard Worker thread->start("RenderThread");
221*d57664e9SAndroid Build Coastguard Worker return thread;
222*d57664e9SAndroid Build Coastguard Worker }();
223*d57664e9SAndroid Build Coastguard Worker gHasRenderThreadInstance = true;
224*d57664e9SAndroid Build Coastguard Worker return *sInstance;
225*d57664e9SAndroid Build Coastguard Worker }
226*d57664e9SAndroid Build Coastguard Worker
RenderThread()227*d57664e9SAndroid Build Coastguard Worker RenderThread::RenderThread()
228*d57664e9SAndroid Build Coastguard Worker : ThreadBase()
229*d57664e9SAndroid Build Coastguard Worker , mVsyncSource(nullptr)
230*d57664e9SAndroid Build Coastguard Worker , mVsyncRequested(false)
231*d57664e9SAndroid Build Coastguard Worker , mFrameCallbackTaskPending(false)
232*d57664e9SAndroid Build Coastguard Worker , mRenderState(nullptr)
233*d57664e9SAndroid Build Coastguard Worker , mEglManager(nullptr)
234*d57664e9SAndroid Build Coastguard Worker , mFunctorManager(WebViewFunctorManager::instance())
235*d57664e9SAndroid Build Coastguard Worker , mGlobalProfileData(mJankDataMutex) {
236*d57664e9SAndroid Build Coastguard Worker Properties::load();
237*d57664e9SAndroid Build Coastguard Worker }
238*d57664e9SAndroid Build Coastguard Worker
~RenderThread()239*d57664e9SAndroid Build Coastguard Worker RenderThread::~RenderThread() {
240*d57664e9SAndroid Build Coastguard Worker // Note that if this fatal assertion is removed then member variables must
241*d57664e9SAndroid Build Coastguard Worker // be properly destroyed.
242*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("Can't destroy the render thread");
243*d57664e9SAndroid Build Coastguard Worker }
244*d57664e9SAndroid Build Coastguard Worker
initializeChoreographer()245*d57664e9SAndroid Build Coastguard Worker void RenderThread::initializeChoreographer() {
246*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(mVsyncSource, "Initializing a second Choreographer?");
247*d57664e9SAndroid Build Coastguard Worker
248*d57664e9SAndroid Build Coastguard Worker if (!Properties::isolatedProcess) {
249*d57664e9SAndroid Build Coastguard Worker mChoreographer = AChoreographer_create();
250*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(mChoreographer == nullptr, "Initialization of Choreographer failed");
251*d57664e9SAndroid Build Coastguard Worker AChoreographer_registerRefreshRateCallback(mChoreographer,
252*d57664e9SAndroid Build Coastguard Worker RenderThread::refreshRateCallback, this);
253*d57664e9SAndroid Build Coastguard Worker
254*d57664e9SAndroid Build Coastguard Worker // Register the FD
255*d57664e9SAndroid Build Coastguard Worker mLooper->addFd(AChoreographer_getFd(mChoreographer), 0, Looper::EVENT_INPUT,
256*d57664e9SAndroid Build Coastguard Worker RenderThread::choreographerCallback, this);
257*d57664e9SAndroid Build Coastguard Worker mVsyncSource = new ChoreographerSource(this);
258*d57664e9SAndroid Build Coastguard Worker } else {
259*d57664e9SAndroid Build Coastguard Worker mVsyncSource = new DummyVsyncSource(this);
260*d57664e9SAndroid Build Coastguard Worker }
261*d57664e9SAndroid Build Coastguard Worker }
262*d57664e9SAndroid Build Coastguard Worker
initThreadLocals()263*d57664e9SAndroid Build Coastguard Worker void RenderThread::initThreadLocals() {
264*d57664e9SAndroid Build Coastguard Worker setupFrameInterval();
265*d57664e9SAndroid Build Coastguard Worker initializeChoreographer();
266*d57664e9SAndroid Build Coastguard Worker mEglManager = new EglManager();
267*d57664e9SAndroid Build Coastguard Worker mRenderState = new RenderState(*this);
268*d57664e9SAndroid Build Coastguard Worker mVkManager = VulkanManager::getInstance();
269*d57664e9SAndroid Build Coastguard Worker mCacheManager = new CacheManager(*this);
270*d57664e9SAndroid Build Coastguard Worker }
271*d57664e9SAndroid Build Coastguard Worker
setupFrameInterval()272*d57664e9SAndroid Build Coastguard Worker void RenderThread::setupFrameInterval() {
273*d57664e9SAndroid Build Coastguard Worker nsecs_t frameIntervalNanos = DeviceInfo::getVsyncPeriod();
274*d57664e9SAndroid Build Coastguard Worker mTimeLord.setFrameInterval(frameIntervalNanos);
275*d57664e9SAndroid Build Coastguard Worker }
276*d57664e9SAndroid Build Coastguard Worker
requireGlContext()277*d57664e9SAndroid Build Coastguard Worker void RenderThread::requireGlContext() {
278*d57664e9SAndroid Build Coastguard Worker if (mEglManager->hasEglContext()) {
279*d57664e9SAndroid Build Coastguard Worker return;
280*d57664e9SAndroid Build Coastguard Worker }
281*d57664e9SAndroid Build Coastguard Worker mEglManager->initialize();
282*d57664e9SAndroid Build Coastguard Worker
283*d57664e9SAndroid Build Coastguard Worker sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface();
284*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(!glInterface.get());
285*d57664e9SAndroid Build Coastguard Worker
286*d57664e9SAndroid Build Coastguard Worker GrContextOptions options;
287*d57664e9SAndroid Build Coastguard Worker initGrContextOptions(options);
288*d57664e9SAndroid Build Coastguard Worker auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
289*d57664e9SAndroid Build Coastguard Worker auto size = glesVersion ? strlen(glesVersion) : -1;
290*d57664e9SAndroid Build Coastguard Worker cacheManager().configureContext(&options, glesVersion, size);
291*d57664e9SAndroid Build Coastguard Worker sk_sp<GrDirectContext> grContext(GrDirectContexts::MakeGL(std::move(glInterface), options));
292*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(!grContext.get());
293*d57664e9SAndroid Build Coastguard Worker setGrContext(grContext);
294*d57664e9SAndroid Build Coastguard Worker }
295*d57664e9SAndroid Build Coastguard Worker
requireVkContext()296*d57664e9SAndroid Build Coastguard Worker void RenderThread::requireVkContext() {
297*d57664e9SAndroid Build Coastguard Worker // the getter creates the context in the event it had been destroyed by destroyRenderingContext
298*d57664e9SAndroid Build Coastguard Worker // Also check if we have a GrContext before returning fast. VulkanManager may be shared with
299*d57664e9SAndroid Build Coastguard Worker // the HardwareBitmapUploader which initializes the Vk context without persisting the GrContext
300*d57664e9SAndroid Build Coastguard Worker // in the rendering thread.
301*d57664e9SAndroid Build Coastguard Worker if (vulkanManager().hasVkContext() && mGrContext) {
302*d57664e9SAndroid Build Coastguard Worker return;
303*d57664e9SAndroid Build Coastguard Worker }
304*d57664e9SAndroid Build Coastguard Worker mVkManager->initialize();
305*d57664e9SAndroid Build Coastguard Worker GrContextOptions options;
306*d57664e9SAndroid Build Coastguard Worker initGrContextOptions(options);
307*d57664e9SAndroid Build Coastguard Worker auto vkDriverVersion = mVkManager->getDriverVersion();
308*d57664e9SAndroid Build Coastguard Worker cacheManager().configureContext(&options, &vkDriverVersion, sizeof(vkDriverVersion));
309*d57664e9SAndroid Build Coastguard Worker sk_sp<GrDirectContext> grContext = mVkManager->createContext(options);
310*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(!grContext.get());
311*d57664e9SAndroid Build Coastguard Worker setGrContext(grContext);
312*d57664e9SAndroid Build Coastguard Worker }
313*d57664e9SAndroid Build Coastguard Worker
initGrContextOptions(GrContextOptions & options)314*d57664e9SAndroid Build Coastguard Worker void RenderThread::initGrContextOptions(GrContextOptions& options) {
315*d57664e9SAndroid Build Coastguard Worker options.fPreferExternalImagesOverES3 = true;
316*d57664e9SAndroid Build Coastguard Worker options.fDisableDistanceFieldPaths = true;
317*d57664e9SAndroid Build Coastguard Worker if (android::base::GetBoolProperty(PROPERTY_REDUCE_OPS_TASK_SPLITTING, true)) {
318*d57664e9SAndroid Build Coastguard Worker options.fReduceOpsTaskSplitting = GrContextOptions::Enable::kYes;
319*d57664e9SAndroid Build Coastguard Worker } else {
320*d57664e9SAndroid Build Coastguard Worker options.fReduceOpsTaskSplitting = GrContextOptions::Enable::kNo;
321*d57664e9SAndroid Build Coastguard Worker }
322*d57664e9SAndroid Build Coastguard Worker }
323*d57664e9SAndroid Build Coastguard Worker
destroyRenderingContext()324*d57664e9SAndroid Build Coastguard Worker void RenderThread::destroyRenderingContext() {
325*d57664e9SAndroid Build Coastguard Worker mFunctorManager.onContextDestroyed();
326*d57664e9SAndroid Build Coastguard Worker if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
327*d57664e9SAndroid Build Coastguard Worker if (mEglManager->hasEglContext()) {
328*d57664e9SAndroid Build Coastguard Worker setGrContext(nullptr);
329*d57664e9SAndroid Build Coastguard Worker mEglManager->destroy();
330*d57664e9SAndroid Build Coastguard Worker }
331*d57664e9SAndroid Build Coastguard Worker } else {
332*d57664e9SAndroid Build Coastguard Worker setGrContext(nullptr);
333*d57664e9SAndroid Build Coastguard Worker mVkManager.clear();
334*d57664e9SAndroid Build Coastguard Worker }
335*d57664e9SAndroid Build Coastguard Worker }
336*d57664e9SAndroid Build Coastguard Worker
vulkanManager()337*d57664e9SAndroid Build Coastguard Worker VulkanManager& RenderThread::vulkanManager() {
338*d57664e9SAndroid Build Coastguard Worker if (!mVkManager.get()) {
339*d57664e9SAndroid Build Coastguard Worker mVkManager = VulkanManager::getInstance();
340*d57664e9SAndroid Build Coastguard Worker }
341*d57664e9SAndroid Build Coastguard Worker return *mVkManager.get();
342*d57664e9SAndroid Build Coastguard Worker }
343*d57664e9SAndroid Build Coastguard Worker
pipelineToString()344*d57664e9SAndroid Build Coastguard Worker static const char* pipelineToString() {
345*d57664e9SAndroid Build Coastguard Worker switch (auto renderType = Properties::getRenderPipelineType()) {
346*d57664e9SAndroid Build Coastguard Worker case RenderPipelineType::SkiaGL:
347*d57664e9SAndroid Build Coastguard Worker return "Skia (OpenGL)";
348*d57664e9SAndroid Build Coastguard Worker case RenderPipelineType::SkiaVulkan:
349*d57664e9SAndroid Build Coastguard Worker return "Skia (Vulkan)";
350*d57664e9SAndroid Build Coastguard Worker default:
351*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
352*d57664e9SAndroid Build Coastguard Worker }
353*d57664e9SAndroid Build Coastguard Worker }
354*d57664e9SAndroid Build Coastguard Worker
dumpGraphicsMemory(int fd,bool includeProfileData)355*d57664e9SAndroid Build Coastguard Worker void RenderThread::dumpGraphicsMemory(int fd, bool includeProfileData) {
356*d57664e9SAndroid Build Coastguard Worker if (includeProfileData) {
357*d57664e9SAndroid Build Coastguard Worker globalProfileData()->dump(fd);
358*d57664e9SAndroid Build Coastguard Worker }
359*d57664e9SAndroid Build Coastguard Worker
360*d57664e9SAndroid Build Coastguard Worker String8 cachesOutput;
361*d57664e9SAndroid Build Coastguard Worker mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
362*d57664e9SAndroid Build Coastguard Worker dprintf(fd, "\nPipeline=%s\n%s", pipelineToString(), cachesOutput.c_str());
363*d57664e9SAndroid Build Coastguard Worker for (auto&& context : mCacheManager->mCanvasContexts) {
364*d57664e9SAndroid Build Coastguard Worker context->visitAllRenderNodes([&](const RenderNode& node) {
365*d57664e9SAndroid Build Coastguard Worker if (node.isTextureView()) {
366*d57664e9SAndroid Build Coastguard Worker dprintf(fd, "TextureView: %dx%d\n", node.getWidth(), node.getHeight());
367*d57664e9SAndroid Build Coastguard Worker }
368*d57664e9SAndroid Build Coastguard Worker });
369*d57664e9SAndroid Build Coastguard Worker }
370*d57664e9SAndroid Build Coastguard Worker dprintf(fd, "\n");
371*d57664e9SAndroid Build Coastguard Worker }
372*d57664e9SAndroid Build Coastguard Worker
getMemoryUsage(size_t * cpuUsage,size_t * gpuUsage)373*d57664e9SAndroid Build Coastguard Worker void RenderThread::getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage) {
374*d57664e9SAndroid Build Coastguard Worker mCacheManager->getMemoryUsage(cpuUsage, gpuUsage);
375*d57664e9SAndroid Build Coastguard Worker }
376*d57664e9SAndroid Build Coastguard Worker
readback()377*d57664e9SAndroid Build Coastguard Worker Readback& RenderThread::readback() {
378*d57664e9SAndroid Build Coastguard Worker if (!mReadback) {
379*d57664e9SAndroid Build Coastguard Worker mReadback = new Readback(*this);
380*d57664e9SAndroid Build Coastguard Worker }
381*d57664e9SAndroid Build Coastguard Worker
382*d57664e9SAndroid Build Coastguard Worker return *mReadback;
383*d57664e9SAndroid Build Coastguard Worker }
384*d57664e9SAndroid Build Coastguard Worker
setGrContext(sk_sp<GrDirectContext> context)385*d57664e9SAndroid Build Coastguard Worker void RenderThread::setGrContext(sk_sp<GrDirectContext> context) {
386*d57664e9SAndroid Build Coastguard Worker mCacheManager->reset(context);
387*d57664e9SAndroid Build Coastguard Worker if (mGrContext) {
388*d57664e9SAndroid Build Coastguard Worker mRenderState->onContextDestroyed();
389*d57664e9SAndroid Build Coastguard Worker mGrContext->releaseResourcesAndAbandonContext();
390*d57664e9SAndroid Build Coastguard Worker }
391*d57664e9SAndroid Build Coastguard Worker mGrContext = std::move(context);
392*d57664e9SAndroid Build Coastguard Worker if (mGrContext) {
393*d57664e9SAndroid Build Coastguard Worker DeviceInfo::setMaxTextureSize(mGrContext->maxRenderTargetSize());
394*d57664e9SAndroid Build Coastguard Worker }
395*d57664e9SAndroid Build Coastguard Worker }
396*d57664e9SAndroid Build Coastguard Worker
requireGrContext()397*d57664e9SAndroid Build Coastguard Worker sk_sp<GrDirectContext> RenderThread::requireGrContext() {
398*d57664e9SAndroid Build Coastguard Worker if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
399*d57664e9SAndroid Build Coastguard Worker requireGlContext();
400*d57664e9SAndroid Build Coastguard Worker } else {
401*d57664e9SAndroid Build Coastguard Worker requireVkContext();
402*d57664e9SAndroid Build Coastguard Worker }
403*d57664e9SAndroid Build Coastguard Worker return mGrContext;
404*d57664e9SAndroid Build Coastguard Worker }
405*d57664e9SAndroid Build Coastguard Worker
choreographerCallback(int fd,int events,void * data)406*d57664e9SAndroid Build Coastguard Worker int RenderThread::choreographerCallback(int fd, int events, void* data) {
407*d57664e9SAndroid Build Coastguard Worker if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
408*d57664e9SAndroid Build Coastguard Worker ALOGE("Display event receiver pipe was closed or an error occurred. "
409*d57664e9SAndroid Build Coastguard Worker "events=0x%x",
410*d57664e9SAndroid Build Coastguard Worker events);
411*d57664e9SAndroid Build Coastguard Worker return 0; // remove the callback
412*d57664e9SAndroid Build Coastguard Worker }
413*d57664e9SAndroid Build Coastguard Worker
414*d57664e9SAndroid Build Coastguard Worker if (!(events & Looper::EVENT_INPUT)) {
415*d57664e9SAndroid Build Coastguard Worker ALOGW("Received spurious callback for unhandled poll event. "
416*d57664e9SAndroid Build Coastguard Worker "events=0x%x",
417*d57664e9SAndroid Build Coastguard Worker events);
418*d57664e9SAndroid Build Coastguard Worker return 1; // keep the callback
419*d57664e9SAndroid Build Coastguard Worker }
420*d57664e9SAndroid Build Coastguard Worker RenderThread* rt = reinterpret_cast<RenderThread*>(data);
421*d57664e9SAndroid Build Coastguard Worker AChoreographer_handlePendingEvents(rt->mChoreographer, data);
422*d57664e9SAndroid Build Coastguard Worker
423*d57664e9SAndroid Build Coastguard Worker return 1;
424*d57664e9SAndroid Build Coastguard Worker }
425*d57664e9SAndroid Build Coastguard Worker
dispatchFrameCallbacks()426*d57664e9SAndroid Build Coastguard Worker void RenderThread::dispatchFrameCallbacks() {
427*d57664e9SAndroid Build Coastguard Worker ATRACE_CALL();
428*d57664e9SAndroid Build Coastguard Worker mFrameCallbackTaskPending = false;
429*d57664e9SAndroid Build Coastguard Worker
430*d57664e9SAndroid Build Coastguard Worker std::set<IFrameCallback*> callbacks;
431*d57664e9SAndroid Build Coastguard Worker mFrameCallbacks.swap(callbacks);
432*d57664e9SAndroid Build Coastguard Worker
433*d57664e9SAndroid Build Coastguard Worker if (callbacks.size()) {
434*d57664e9SAndroid Build Coastguard Worker // Assume one of them will probably animate again so preemptively
435*d57664e9SAndroid Build Coastguard Worker // request the next vsync in case it occurs mid-frame
436*d57664e9SAndroid Build Coastguard Worker requestVsync();
437*d57664e9SAndroid Build Coastguard Worker for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end();
438*d57664e9SAndroid Build Coastguard Worker it++) {
439*d57664e9SAndroid Build Coastguard Worker (*it)->doFrame();
440*d57664e9SAndroid Build Coastguard Worker }
441*d57664e9SAndroid Build Coastguard Worker }
442*d57664e9SAndroid Build Coastguard Worker }
443*d57664e9SAndroid Build Coastguard Worker
requestVsync()444*d57664e9SAndroid Build Coastguard Worker void RenderThread::requestVsync() {
445*d57664e9SAndroid Build Coastguard Worker if (!mVsyncRequested) {
446*d57664e9SAndroid Build Coastguard Worker mVsyncRequested = true;
447*d57664e9SAndroid Build Coastguard Worker mVsyncSource->requestNextVsync();
448*d57664e9SAndroid Build Coastguard Worker }
449*d57664e9SAndroid Build Coastguard Worker }
450*d57664e9SAndroid Build Coastguard Worker
threadLoop()451*d57664e9SAndroid Build Coastguard Worker bool RenderThread::threadLoop() {
452*d57664e9SAndroid Build Coastguard Worker setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
453*d57664e9SAndroid Build Coastguard Worker Looper::setForThread(mLooper);
454*d57664e9SAndroid Build Coastguard Worker if (gOnStartHook) {
455*d57664e9SAndroid Build Coastguard Worker gOnStartHook("RenderThread");
456*d57664e9SAndroid Build Coastguard Worker }
457*d57664e9SAndroid Build Coastguard Worker initThreadLocals();
458*d57664e9SAndroid Build Coastguard Worker
459*d57664e9SAndroid Build Coastguard Worker while (true) {
460*d57664e9SAndroid Build Coastguard Worker waitForWork();
461*d57664e9SAndroid Build Coastguard Worker processQueue();
462*d57664e9SAndroid Build Coastguard Worker
463*d57664e9SAndroid Build Coastguard Worker if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
464*d57664e9SAndroid Build Coastguard Worker mVsyncSource->drainPendingEvents();
465*d57664e9SAndroid Build Coastguard Worker mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
466*d57664e9SAndroid Build Coastguard Worker mPendingRegistrationFrameCallbacks.end());
467*d57664e9SAndroid Build Coastguard Worker mPendingRegistrationFrameCallbacks.clear();
468*d57664e9SAndroid Build Coastguard Worker requestVsync();
469*d57664e9SAndroid Build Coastguard Worker }
470*d57664e9SAndroid Build Coastguard Worker
471*d57664e9SAndroid Build Coastguard Worker if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
472*d57664e9SAndroid Build Coastguard Worker // TODO: Clean this up. This is working around an issue where a combination
473*d57664e9SAndroid Build Coastguard Worker // of bad timing and slow drawing can result in dropping a stale vsync
474*d57664e9SAndroid Build Coastguard Worker // on the floor (correct!) but fails to schedule to listen for the
475*d57664e9SAndroid Build Coastguard Worker // next vsync (oops), so none of the callbacks are run.
476*d57664e9SAndroid Build Coastguard Worker requestVsync();
477*d57664e9SAndroid Build Coastguard Worker }
478*d57664e9SAndroid Build Coastguard Worker
479*d57664e9SAndroid Build Coastguard Worker mCacheManager->onThreadIdle();
480*d57664e9SAndroid Build Coastguard Worker }
481*d57664e9SAndroid Build Coastguard Worker
482*d57664e9SAndroid Build Coastguard Worker return false;
483*d57664e9SAndroid Build Coastguard Worker }
484*d57664e9SAndroid Build Coastguard Worker
postFrameCallback(IFrameCallback * callback)485*d57664e9SAndroid Build Coastguard Worker void RenderThread::postFrameCallback(IFrameCallback* callback) {
486*d57664e9SAndroid Build Coastguard Worker mPendingRegistrationFrameCallbacks.insert(callback);
487*d57664e9SAndroid Build Coastguard Worker }
488*d57664e9SAndroid Build Coastguard Worker
removeFrameCallback(IFrameCallback * callback)489*d57664e9SAndroid Build Coastguard Worker bool RenderThread::removeFrameCallback(IFrameCallback* callback) {
490*d57664e9SAndroid Build Coastguard Worker size_t erased;
491*d57664e9SAndroid Build Coastguard Worker erased = mFrameCallbacks.erase(callback);
492*d57664e9SAndroid Build Coastguard Worker erased |= mPendingRegistrationFrameCallbacks.erase(callback);
493*d57664e9SAndroid Build Coastguard Worker return erased;
494*d57664e9SAndroid Build Coastguard Worker }
495*d57664e9SAndroid Build Coastguard Worker
pushBackFrameCallback(IFrameCallback * callback)496*d57664e9SAndroid Build Coastguard Worker void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
497*d57664e9SAndroid Build Coastguard Worker if (mFrameCallbacks.erase(callback)) {
498*d57664e9SAndroid Build Coastguard Worker mPendingRegistrationFrameCallbacks.insert(callback);
499*d57664e9SAndroid Build Coastguard Worker }
500*d57664e9SAndroid Build Coastguard Worker }
501*d57664e9SAndroid Build Coastguard Worker
allocateHardwareBitmap(SkBitmap & skBitmap)502*d57664e9SAndroid Build Coastguard Worker sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) {
503*d57664e9SAndroid Build Coastguard Worker auto renderType = Properties::getRenderPipelineType();
504*d57664e9SAndroid Build Coastguard Worker switch (renderType) {
505*d57664e9SAndroid Build Coastguard Worker case RenderPipelineType::SkiaVulkan:
506*d57664e9SAndroid Build Coastguard Worker return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap);
507*d57664e9SAndroid Build Coastguard Worker default:
508*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
509*d57664e9SAndroid Build Coastguard Worker break;
510*d57664e9SAndroid Build Coastguard Worker }
511*d57664e9SAndroid Build Coastguard Worker return nullptr;
512*d57664e9SAndroid Build Coastguard Worker }
513*d57664e9SAndroid Build Coastguard Worker
isCurrent()514*d57664e9SAndroid Build Coastguard Worker bool RenderThread::isCurrent() {
515*d57664e9SAndroid Build Coastguard Worker return gettid() == getInstance().getTid();
516*d57664e9SAndroid Build Coastguard Worker }
517*d57664e9SAndroid Build Coastguard Worker
preload()518*d57664e9SAndroid Build Coastguard Worker void RenderThread::preload() {
519*d57664e9SAndroid Build Coastguard Worker // EGL driver is always preloaded only if HWUI renders with GL.
520*d57664e9SAndroid Build Coastguard Worker if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
521*d57664e9SAndroid Build Coastguard Worker std::thread eglInitThread([]() { eglGetDisplay(EGL_DEFAULT_DISPLAY); });
522*d57664e9SAndroid Build Coastguard Worker eglInitThread.detach();
523*d57664e9SAndroid Build Coastguard Worker } else {
524*d57664e9SAndroid Build Coastguard Worker requireVkContext();
525*d57664e9SAndroid Build Coastguard Worker }
526*d57664e9SAndroid Build Coastguard Worker HardwareBitmapUploader::initialize();
527*d57664e9SAndroid Build Coastguard Worker }
528*d57664e9SAndroid Build Coastguard Worker
trimMemory(TrimLevel level)529*d57664e9SAndroid Build Coastguard Worker void RenderThread::trimMemory(TrimLevel level) {
530*d57664e9SAndroid Build Coastguard Worker ATRACE_CALL();
531*d57664e9SAndroid Build Coastguard Worker cacheManager().trimMemory(level);
532*d57664e9SAndroid Build Coastguard Worker }
533*d57664e9SAndroid Build Coastguard Worker
trimCaches(CacheTrimLevel level)534*d57664e9SAndroid Build Coastguard Worker void RenderThread::trimCaches(CacheTrimLevel level) {
535*d57664e9SAndroid Build Coastguard Worker ATRACE_CALL();
536*d57664e9SAndroid Build Coastguard Worker cacheManager().trimCaches(level);
537*d57664e9SAndroid Build Coastguard Worker }
538*d57664e9SAndroid Build Coastguard Worker
539*d57664e9SAndroid Build Coastguard Worker } /* namespace renderthread */
540*d57664e9SAndroid Build Coastguard Worker } /* namespace uirenderer */
541*d57664e9SAndroid Build Coastguard Worker } /* namespace android */
542