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 "../HardwareBitmapUploader.h"
20 #include "CanvasContext.h"
21 #include "DeviceInfo.h"
22 #include "EglManager.h"
23 #include "Readback.h"
24 #include "RenderProxy.h"
25 #include "VulkanManager.h"
26 #include "hwui/Bitmap.h"
27 #include "pipeline/skia/SkiaOpenGLPipeline.h"
28 #include "pipeline/skia/SkiaVulkanPipeline.h"
29 #include "renderstate/RenderState.h"
30 #include "utils/TimeUtils.h"
31 #include "utils/TraceUtils.h"
32 
33 #include <GrContextOptions.h>
34 #include <gl/GrGLInterface.h>
35 
36 #include <sys/resource.h>
37 #include <utils/Condition.h>
38 #include <utils/Log.h>
39 #include <utils/Mutex.h>
40 #include <thread>
41 
42 #include <ui/FatVector.h>
43 
44 namespace android {
45 namespace uirenderer {
46 namespace renderthread {
47 
48 static bool gHasRenderThreadInstance = false;
49 
50 static JVMAttachHook gOnStartHook = nullptr;
51 
frameCallback(int64_t frameTimeNanos,void * data)52 void RenderThread::frameCallback(int64_t frameTimeNanos, void* data) {
53     RenderThread* rt = reinterpret_cast<RenderThread*>(data);
54     rt->mVsyncRequested = false;
55     if (rt->timeLord().vsyncReceived(frameTimeNanos) && !rt->mFrameCallbackTaskPending) {
56         ATRACE_NAME("queue mFrameCallbackTask");
57         rt->mFrameCallbackTaskPending = true;
58         nsecs_t runAt = (frameTimeNanos + rt->mDispatchFrameDelay);
59         rt->queue().postAt(runAt, [=]() { rt->dispatchFrameCallbacks(); });
60     }
61 }
62 
refreshRateCallback(int64_t vsyncPeriod,void * data)63 void RenderThread::refreshRateCallback(int64_t vsyncPeriod, void* data) {
64     ATRACE_NAME("refreshRateCallback");
65     RenderThread* rt = reinterpret_cast<RenderThread*>(data);
66     DeviceInfo::get()->onRefreshRateChanged(vsyncPeriod);
67     rt->setupFrameInterval();
68 }
69 
70 class ChoreographerSource : public VsyncSource {
71 public:
ChoreographerSource(RenderThread * renderThread)72     ChoreographerSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
73 
requestNextVsync()74     virtual void requestNextVsync() override {
75         AChoreographer_postFrameCallback64(mRenderThread->mChoreographer,
76                                            RenderThread::frameCallback, mRenderThread);
77     }
78 
drainPendingEvents()79     virtual void drainPendingEvents() override {
80         AChoreographer_handlePendingEvents(mRenderThread->mChoreographer, mRenderThread);
81     }
82 
83 private:
84     RenderThread* mRenderThread;
85 };
86 
87 class DummyVsyncSource : public VsyncSource {
88 public:
DummyVsyncSource(RenderThread * renderThread)89     DummyVsyncSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
90 
requestNextVsync()91     virtual void requestNextVsync() override {
92         mRenderThread->queue().postDelayed(16_ms, [this]() {
93             RenderThread::frameCallback(systemTime(SYSTEM_TIME_MONOTONIC), mRenderThread);
94         });
95     }
96 
drainPendingEvents()97     virtual void drainPendingEvents() override {
98         RenderThread::frameCallback(systemTime(SYSTEM_TIME_MONOTONIC), mRenderThread);
99     }
100 
101 private:
102     RenderThread* mRenderThread;
103 };
104 
hasInstance()105 bool RenderThread::hasInstance() {
106     return gHasRenderThreadInstance;
107 }
108 
setOnStartHook(JVMAttachHook onStartHook)109 void RenderThread::setOnStartHook(JVMAttachHook onStartHook) {
110     LOG_ALWAYS_FATAL_IF(hasInstance(), "can't set an onStartHook after we've started...");
111     gOnStartHook = onStartHook;
112 }
113 
getOnStartHook()114 JVMAttachHook RenderThread::getOnStartHook() {
115     return gOnStartHook;
116 }
117 
getInstance()118 RenderThread& RenderThread::getInstance() {
119     // This is a pointer because otherwise __cxa_finalize
120     // will try to delete it like a Good Citizen but that causes us to crash
121     // because we don't want to delete the RenderThread normally.
122     static RenderThread* sInstance = new RenderThread();
123     gHasRenderThreadInstance = true;
124     return *sInstance;
125 }
126 
RenderThread()127 RenderThread::RenderThread()
128         : ThreadBase()
129         , mVsyncSource(nullptr)
130         , mVsyncRequested(false)
131         , mFrameCallbackTaskPending(false)
132         , mRenderState(nullptr)
133         , mEglManager(nullptr)
134         , mFunctorManager(WebViewFunctorManager::instance())
135         , mVkManager(nullptr) {
136     Properties::load();
137     start("RenderThread");
138 }
139 
~RenderThread()140 RenderThread::~RenderThread() {
141     // Note that if this fatal assertion is removed then member variables must
142     // be properly destroyed.
143     LOG_ALWAYS_FATAL("Can't destroy the render thread");
144 }
145 
initializeChoreographer()146 void RenderThread::initializeChoreographer() {
147     LOG_ALWAYS_FATAL_IF(mVsyncSource, "Initializing a second Choreographer?");
148 
149     if (!Properties::isolatedProcess) {
150         mChoreographer = AChoreographer_create();
151         LOG_ALWAYS_FATAL_IF(mChoreographer == nullptr, "Initialization of Choreographer failed");
152         AChoreographer_registerRefreshRateCallback(mChoreographer,
153                                                    RenderThread::refreshRateCallback, this);
154 
155         // Register the FD
156         mLooper->addFd(AChoreographer_getFd(mChoreographer), 0, Looper::EVENT_INPUT,
157                        RenderThread::choreographerCallback, this);
158         mVsyncSource = new ChoreographerSource(this);
159     } else {
160         mVsyncSource = new DummyVsyncSource(this);
161     }
162 }
163 
initThreadLocals()164 void RenderThread::initThreadLocals() {
165     setupFrameInterval();
166     initializeChoreographer();
167     mEglManager = new EglManager();
168     mRenderState = new RenderState(*this);
169     mVkManager = new VulkanManager();
170     mCacheManager = new CacheManager();
171 }
172 
setupFrameInterval()173 void RenderThread::setupFrameInterval() {
174     nsecs_t frameIntervalNanos = DeviceInfo::getVsyncPeriod();
175     mTimeLord.setFrameInterval(frameIntervalNanos);
176     mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
177 }
178 
requireGlContext()179 void RenderThread::requireGlContext() {
180     if (mEglManager->hasEglContext()) {
181         return;
182     }
183     mEglManager->initialize();
184 
185     sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
186     LOG_ALWAYS_FATAL_IF(!glInterface.get());
187 
188     GrContextOptions options;
189     initGrContextOptions(options);
190     auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
191     auto size = glesVersion ? strlen(glesVersion) : -1;
192     cacheManager().configureContext(&options, glesVersion, size);
193     sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
194     LOG_ALWAYS_FATAL_IF(!grContext.get());
195     setGrContext(grContext);
196 }
197 
requireVkContext()198 void RenderThread::requireVkContext() {
199     if (mVkManager->hasVkContext()) {
200         return;
201     }
202     mVkManager->initialize();
203     GrContextOptions options;
204     initGrContextOptions(options);
205     auto vkDriverVersion = mVkManager->getDriverVersion();
206     cacheManager().configureContext(&options, &vkDriverVersion, sizeof(vkDriverVersion));
207     sk_sp<GrContext> grContext = mVkManager->createContext(options);
208     LOG_ALWAYS_FATAL_IF(!grContext.get());
209     setGrContext(grContext);
210 }
211 
initGrContextOptions(GrContextOptions & options)212 void RenderThread::initGrContextOptions(GrContextOptions& options) {
213     options.fPreferExternalImagesOverES3 = true;
214     options.fDisableDistanceFieldPaths = true;
215 }
216 
destroyRenderingContext()217 void RenderThread::destroyRenderingContext() {
218     mFunctorManager.onContextDestroyed();
219     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
220         if (mEglManager->hasEglContext()) {
221             setGrContext(nullptr);
222             mEglManager->destroy();
223         }
224     } else {
225         if (vulkanManager().hasVkContext()) {
226             setGrContext(nullptr);
227             vulkanManager().destroy();
228         }
229     }
230 }
231 
dumpGraphicsMemory(int fd)232 void RenderThread::dumpGraphicsMemory(int fd) {
233     globalProfileData()->dump(fd);
234 
235     String8 cachesOutput;
236     String8 pipeline;
237     auto renderType = Properties::getRenderPipelineType();
238     switch (renderType) {
239         case RenderPipelineType::SkiaGL: {
240             mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
241             pipeline.appendFormat("Skia (OpenGL)");
242             break;
243         }
244         case RenderPipelineType::SkiaVulkan: {
245             mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
246             pipeline.appendFormat("Skia (Vulkan)");
247             break;
248         }
249         default:
250             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
251             break;
252     }
253 
254     dprintf(fd, "\n%s\n", cachesOutput.string());
255     dprintf(fd, "\nPipeline=%s\n", pipeline.string());
256 }
257 
readback()258 Readback& RenderThread::readback() {
259     if (!mReadback) {
260         mReadback = new Readback(*this);
261     }
262 
263     return *mReadback;
264 }
265 
setGrContext(sk_sp<GrContext> context)266 void RenderThread::setGrContext(sk_sp<GrContext> context) {
267     mCacheManager->reset(context);
268     if (mGrContext) {
269         mRenderState->onContextDestroyed();
270         mGrContext->releaseResourcesAndAbandonContext();
271     }
272     mGrContext = std::move(context);
273     if (mGrContext) {
274         DeviceInfo::setMaxTextureSize(mGrContext->maxRenderTargetSize());
275     }
276 }
277 
choreographerCallback(int fd,int events,void * data)278 int RenderThread::choreographerCallback(int fd, int events, void* data) {
279     if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
280         ALOGE("Display event receiver pipe was closed or an error occurred.  "
281               "events=0x%x",
282               events);
283         return 0;  // remove the callback
284     }
285 
286     if (!(events & Looper::EVENT_INPUT)) {
287         ALOGW("Received spurious callback for unhandled poll event.  "
288               "events=0x%x",
289               events);
290         return 1;  // keep the callback
291     }
292     RenderThread* rt = reinterpret_cast<RenderThread*>(data);
293     AChoreographer_handlePendingEvents(rt->mChoreographer, data);
294 
295     return 1;
296 }
297 
dispatchFrameCallbacks()298 void RenderThread::dispatchFrameCallbacks() {
299     ATRACE_CALL();
300     mFrameCallbackTaskPending = false;
301 
302     std::set<IFrameCallback*> callbacks;
303     mFrameCallbacks.swap(callbacks);
304 
305     if (callbacks.size()) {
306         // Assume one of them will probably animate again so preemptively
307         // request the next vsync in case it occurs mid-frame
308         requestVsync();
309         for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end();
310              it++) {
311             (*it)->doFrame();
312         }
313     }
314 }
315 
requestVsync()316 void RenderThread::requestVsync() {
317     if (!mVsyncRequested) {
318         mVsyncRequested = true;
319         mVsyncSource->requestNextVsync();
320     }
321 }
322 
threadLoop()323 bool RenderThread::threadLoop() {
324     setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
325     Looper::setForThread(mLooper);
326     if (gOnStartHook) {
327         gOnStartHook("RenderThread");
328     }
329     initThreadLocals();
330 
331     while (true) {
332         waitForWork();
333         processQueue();
334 
335         if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
336             mVsyncSource->drainPendingEvents();
337             mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
338                                    mPendingRegistrationFrameCallbacks.end());
339             mPendingRegistrationFrameCallbacks.clear();
340             requestVsync();
341         }
342 
343         if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
344             // TODO: Clean this up. This is working around an issue where a combination
345             // of bad timing and slow drawing can result in dropping a stale vsync
346             // on the floor (correct!) but fails to schedule to listen for the
347             // next vsync (oops), so none of the callbacks are run.
348             requestVsync();
349         }
350     }
351 
352     return false;
353 }
354 
postFrameCallback(IFrameCallback * callback)355 void RenderThread::postFrameCallback(IFrameCallback* callback) {
356     mPendingRegistrationFrameCallbacks.insert(callback);
357 }
358 
removeFrameCallback(IFrameCallback * callback)359 bool RenderThread::removeFrameCallback(IFrameCallback* callback) {
360     size_t erased;
361     erased = mFrameCallbacks.erase(callback);
362     erased |= mPendingRegistrationFrameCallbacks.erase(callback);
363     return erased;
364 }
365 
pushBackFrameCallback(IFrameCallback * callback)366 void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
367     if (mFrameCallbacks.erase(callback)) {
368         mPendingRegistrationFrameCallbacks.insert(callback);
369     }
370 }
371 
allocateHardwareBitmap(SkBitmap & skBitmap)372 sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) {
373     auto renderType = Properties::getRenderPipelineType();
374     switch (renderType) {
375         case RenderPipelineType::SkiaVulkan:
376             return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap);
377         default:
378             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
379             break;
380     }
381     return nullptr;
382 }
383 
isCurrent()384 bool RenderThread::isCurrent() {
385     return gettid() == getInstance().getTid();
386 }
387 
preload()388 void RenderThread::preload() {
389     // EGL driver is always preloaded only if HWUI renders with GL.
390     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
391         std::thread eglInitThread([]() { eglGetDisplay(EGL_DEFAULT_DISPLAY); });
392         eglInitThread.detach();
393     } else {
394         requireVkContext();
395     }
396     HardwareBitmapUploader::initialize();
397 }
398 
399 } /* namespace renderthread */
400 } /* namespace uirenderer */
401 } /* namespace android */
402