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