blob: 79dc09ffbf1d71c0d7f176fc89a303360b62eb0d [file] [log] [blame]
John Reckcec24ae2013-11-05 13:27:50 -08001/*
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
John Reckcec24ae2013-11-05 13:27:50 -080017#include "RenderThread.h"
18
John Reck4f02bf42014-01-03 18:09:17 -080019#include "CanvasContext.h"
John Reck3b202512014-06-23 13:13:08 -070020#include "EglManager.h"
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050021#include "OpenGLReadback.h"
John Reck4f02bf42014-01-03 18:09:17 -080022#include "RenderProxy.h"
Derek Sollenberger0e3cba32016-11-09 11:58:36 -050023#include "VulkanManager.h"
John Reck1bcacfd2017-11-03 10:12:19 -070024#include "hwui/Bitmap.h"
25#include "pipeline/skia/SkiaOpenGLPipeline.h"
26#include "pipeline/skia/SkiaOpenGLReadback.h"
27#include "pipeline/skia/SkiaVulkanPipeline.h"
28#include "renderstate/RenderState.h"
29#include "renderthread/OpenGLPipeline.h"
John Reck12efa552016-11-15 10:22:01 -080030#include "utils/FatVector.h"
John Reckcec24ae2013-11-05 13:27:50 -080031
Chris Craik65fe5ee2015-01-26 18:06:29 -080032#include <gui/DisplayEventReceiver.h>
John Reckb36016c2015-03-11 08:50:53 -070033#include <gui/ISurfaceComposer.h>
34#include <gui/SurfaceComposerClient.h>
Chris Craik65fe5ee2015-01-26 18:06:29 -080035#include <sys/resource.h>
John Reckcba287b2015-11-10 12:52:44 -080036#include <utils/Condition.h>
Chris Craik65fe5ee2015-01-26 18:06:29 -080037#include <utils/Log.h>
John Reckcba287b2015-11-10 12:52:44 -080038#include <utils/Mutex.h>
Chris Craik65fe5ee2015-01-26 18:06:29 -080039
John Reckcec24ae2013-11-05 13:27:50 -080040namespace android {
John Reckcec24ae2013-11-05 13:27:50 -080041namespace uirenderer {
42namespace renderthread {
43
John Recke45b1fd2014-04-15 09:50:16 -070044// Number of events to read at a time from the DisplayEventReceiver pipe.
45// The value should be large enough that we can quickly drain the pipe
46// using just a few large reads.
47static const size_t EVENT_BUFFER_SIZE = 100;
48
49// Slight delay to give the UI time to push us a new frame before we replay
John Recka733f892014-12-19 11:37:21 -080050static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
John Recke45b1fd2014-04-15 09:50:16 -070051
John Reck6b507802015-11-03 10:09:59 -080052static bool gHasRenderThreadInstance = false;
53
John Reck259b25a2017-12-01 16:18:53 -080054static void (*gOnStartHook)() = nullptr;
55
John Reck6b507802015-11-03 10:09:59 -080056bool RenderThread::hasInstance() {
57 return gHasRenderThreadInstance;
58}
59
John Reck259b25a2017-12-01 16:18:53 -080060void RenderThread::setOnStartHook(void (*onStartHook)()) {
61 LOG_ALWAYS_FATAL_IF(hasInstance(), "can't set an onStartHook after we've started...");
62 gOnStartHook = onStartHook;
63}
64
John Reck6b507802015-11-03 10:09:59 -080065RenderThread& RenderThread::getInstance() {
66 // This is a pointer because otherwise __cxa_finalize
67 // will try to delete it like a Good Citizen but that causes us to crash
68 // because we don't want to delete the RenderThread normally.
69 static RenderThread* sInstance = new RenderThread();
70 gHasRenderThreadInstance = true;
71 return *sInstance;
72}
73
John Reck1bcacfd2017-11-03 10:12:19 -070074RenderThread::RenderThread()
75 : ThreadBase()
Chris Craikd41c4d82015-01-05 15:51:13 -080076 , mDisplayEventReceiver(nullptr)
John Recke45b1fd2014-04-15 09:50:16 -070077 , mVsyncRequested(false)
78 , mFrameCallbackTaskPending(false)
Chris Craikd41c4d82015-01-05 15:51:13 -080079 , mRenderState(nullptr)
Derek Sollenberger0e3cba32016-11-09 11:58:36 -050080 , mEglManager(nullptr)
81 , mVkManager(nullptr) {
Chris Craik2507c342015-05-04 14:36:49 -070082 Properties::load();
John Reckf8441e62017-10-23 13:10:41 -070083 start("RenderThread");
John Reckcec24ae2013-11-05 13:27:50 -080084}
85
86RenderThread::~RenderThread() {
John Reck3b202512014-06-23 13:13:08 -070087 LOG_ALWAYS_FATAL("Can't destroy the render thread");
John Reckcec24ae2013-11-05 13:27:50 -080088}
89
John Recke45b1fd2014-04-15 09:50:16 -070090void RenderThread::initializeDisplayEventReceiver() {
91 LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
92 mDisplayEventReceiver = new DisplayEventReceiver();
93 status_t status = mDisplayEventReceiver->initCheck();
John Reck1bcacfd2017-11-03 10:12:19 -070094 LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
95 "Initialization of DisplayEventReceiver "
96 "failed with status: %d",
97 status);
John Recke45b1fd2014-04-15 09:50:16 -070098
99 // Register the FD
John Reck1bcacfd2017-11-03 10:12:19 -0700100 mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT,
101 RenderThread::displayEventReceiverCallback, this);
John Recke45b1fd2014-04-15 09:50:16 -0700102}
103
John Reck3b202512014-06-23 13:13:08 -0700104void RenderThread::initThreadLocals() {
John Reck1bcacfd2017-11-03 10:12:19 -0700105 sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
John Reckb36016c2015-03-11 08:50:53 -0700106 status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
107 LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
108 nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
109 mTimeLord.setFrameInterval(frameIntervalNanos);
John Reck3b202512014-06-23 13:13:08 -0700110 initializeDisplayEventReceiver();
111 mEglManager = new EglManager(*this);
John Reck0e89e2b2014-10-31 14:49:06 -0700112 mRenderState = new RenderState(*this);
Derek Sollenberger0e3cba32016-11-09 11:58:36 -0500113 mVkManager = new VulkanManager(*this);
Derek Sollenbergerf9e45d12017-06-01 13:07:39 -0400114 mCacheManager = new CacheManager(mDisplayInfo);
115}
116
117void RenderThread::dumpGraphicsMemory(int fd) {
John Reck34781b22017-07-05 16:39:36 -0700118 globalProfileData()->dump(fd);
Derek Sollenbergerf9e45d12017-06-01 13:07:39 -0400119
120 String8 cachesOutput;
121 String8 pipeline;
122 auto renderType = Properties::getRenderPipelineType();
123 switch (renderType) {
124 case RenderPipelineType::OpenGL: {
125 if (Caches::hasInstance()) {
126 cachesOutput.appendFormat("Caches:\n");
127 Caches::getInstance().dumpMemoryUsage(cachesOutput);
128 } else {
129 cachesOutput.appendFormat("No caches instance.");
130 }
131 pipeline.appendFormat("FrameBuilder");
132 break;
133 }
134 case RenderPipelineType::SkiaGL: {
135 mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
136 pipeline.appendFormat("Skia (OpenGL)");
137 break;
138 }
139 case RenderPipelineType::SkiaVulkan: {
140 mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
141 pipeline.appendFormat("Skia (Vulkan)");
142 break;
143 }
144 default:
John Reck1bcacfd2017-11-03 10:12:19 -0700145 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
Derek Sollenbergerf9e45d12017-06-01 13:07:39 -0400146 break;
147 }
148
John Reck47f5c3a2017-11-13 11:32:39 -0800149 dprintf(fd, "\n%s\n", cachesOutput.string());
150 dprintf(fd, "\nPipeline=%s\n", pipeline.string());
John Reck3b202512014-06-23 13:13:08 -0700151}
152
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -0500153Readback& RenderThread::readback() {
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -0500154 if (!mReadback) {
155 auto renderType = Properties::getRenderPipelineType();
156 switch (renderType) {
157 case RenderPipelineType::OpenGL:
158 mReadback = new OpenGLReadbackImpl(*this);
159 break;
160 case RenderPipelineType::SkiaGL:
161 case RenderPipelineType::SkiaVulkan:
162 // It works to use the OpenGL pipeline for Vulkan but this is not
163 // ideal as it causes us to create an OpenGL context in addition
164 // to the Vulkan one.
165 mReadback = new skiapipeline::SkiaOpenGLReadback(*this);
166 break;
167 default:
John Reck1bcacfd2017-11-03 10:12:19 -0700168 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -0500169 break;
170 }
171 }
172
173 return *mReadback;
174}
175
Greg Daniel660d6ec2017-12-08 11:44:27 -0500176void RenderThread::setGrContext(sk_sp<GrContext> context) {
Derek Sollenbergerf9e45d12017-06-01 13:07:39 -0400177 mCacheManager->reset(context);
Greg Daniel660d6ec2017-12-08 11:44:27 -0500178 if (mGrContext) {
Derek Sollenbergerf9e45d12017-06-01 13:07:39 -0400179 mGrContext->releaseResourcesAndAbandonContext();
180 }
Greg Daniel660d6ec2017-12-08 11:44:27 -0500181 mGrContext = std::move(context);
Derek Sollenbergerf9e45d12017-06-01 13:07:39 -0400182}
183
John Recke45b1fd2014-04-15 09:50:16 -0700184int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
185 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
186 ALOGE("Display event receiver pipe was closed or an error occurred. "
John Reck1bcacfd2017-11-03 10:12:19 -0700187 "events=0x%x",
188 events);
189 return 0; // remove the callback
John Recke45b1fd2014-04-15 09:50:16 -0700190 }
191
192 if (!(events & Looper::EVENT_INPUT)) {
193 ALOGW("Received spurious callback for unhandled poll event. "
John Reck1bcacfd2017-11-03 10:12:19 -0700194 "events=0x%x",
195 events);
196 return 1; // keep the callback
John Recke45b1fd2014-04-15 09:50:16 -0700197 }
198
199 reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
200
John Reck1bcacfd2017-11-03 10:12:19 -0700201 return 1; // keep the callback
John Recke45b1fd2014-04-15 09:50:16 -0700202}
203
204static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
205 DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
206 nsecs_t latest = 0;
207 ssize_t n;
208 while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
209 for (ssize_t i = 0; i < n; i++) {
210 const DisplayEventReceiver::Event& ev = buf[i];
211 switch (ev.header.type) {
John Reck1bcacfd2017-11-03 10:12:19 -0700212 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
213 latest = ev.header.timestamp;
214 break;
John Recke45b1fd2014-04-15 09:50:16 -0700215 }
216 }
217 }
218 if (n < 0) {
219 ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
220 }
221 return latest;
222}
223
John Recka733f892014-12-19 11:37:21 -0800224void RenderThread::drainDisplayEventQueue() {
John Recka5dda642014-05-22 15:43:54 -0700225 ATRACE_CALL();
John Recke45b1fd2014-04-15 09:50:16 -0700226 nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
227 if (vsyncEvent > 0) {
228 mVsyncRequested = false;
John Recka733f892014-12-19 11:37:21 -0800229 if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
John Recka5dda642014-05-22 15:43:54 -0700230 ATRACE_NAME("queue mFrameCallbackTask");
John Recke45b1fd2014-04-15 09:50:16 -0700231 mFrameCallbackTaskPending = true;
John Recka733f892014-12-19 11:37:21 -0800232 nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
John Reck1bcacfd2017-11-03 10:12:19 -0700233 queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); });
John Recke45b1fd2014-04-15 09:50:16 -0700234 }
235 }
236}
237
238void RenderThread::dispatchFrameCallbacks() {
John Recka5dda642014-05-22 15:43:54 -0700239 ATRACE_CALL();
John Recke45b1fd2014-04-15 09:50:16 -0700240 mFrameCallbackTaskPending = false;
241
242 std::set<IFrameCallback*> callbacks;
243 mFrameCallbacks.swap(callbacks);
244
John Recka733f892014-12-19 11:37:21 -0800245 if (callbacks.size()) {
246 // Assume one of them will probably animate again so preemptively
247 // request the next vsync in case it occurs mid-frame
248 requestVsync();
John Reck1bcacfd2017-11-03 10:12:19 -0700249 for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end();
250 it++) {
John Recka733f892014-12-19 11:37:21 -0800251 (*it)->doFrame();
252 }
John Recke45b1fd2014-04-15 09:50:16 -0700253 }
254}
255
John Recka5dda642014-05-22 15:43:54 -0700256void RenderThread::requestVsync() {
257 if (!mVsyncRequested) {
258 mVsyncRequested = true;
259 status_t status = mDisplayEventReceiver->requestNextVsync();
John Reck1bcacfd2017-11-03 10:12:19 -0700260 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "requestNextVsync failed with status: %d", status);
John Recka5dda642014-05-22 15:43:54 -0700261 }
262}
263
John Reckcec24ae2013-11-05 13:27:50 -0800264bool RenderThread::threadLoop() {
John Reck21be43e2014-08-14 10:25:16 -0700265 setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
John Reck259b25a2017-12-01 16:18:53 -0800266 if (gOnStartHook) {
267 gOnStartHook();
268 }
John Reck3b202512014-06-23 13:13:08 -0700269 initThreadLocals();
John Recke45b1fd2014-04-15 09:50:16 -0700270
John Reckf8441e62017-10-23 13:10:41 -0700271 while (true) {
272 waitForWork();
273 processQueue();
John Recka5dda642014-05-22 15:43:54 -0700274
275 if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
John Recka733f892014-12-19 11:37:21 -0800276 drainDisplayEventQueue();
John Reck1bcacfd2017-11-03 10:12:19 -0700277 mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
278 mPendingRegistrationFrameCallbacks.end());
John Recka5dda642014-05-22 15:43:54 -0700279 mPendingRegistrationFrameCallbacks.clear();
280 requestVsync();
281 }
John Recka22c9b22015-01-14 10:40:15 -0800282
283 if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
284 // TODO: Clean this up. This is working around an issue where a combination
285 // of bad timing and slow drawing can result in dropping a stale vsync
286 // on the floor (correct!) but fails to schedule to listen for the
287 // next vsync (oops), so none of the callbacks are run.
288 requestVsync();
289 }
John Reckcec24ae2013-11-05 13:27:50 -0800290 }
291
292 return false;
293}
294
John Recke45b1fd2014-04-15 09:50:16 -0700295void RenderThread::postFrameCallback(IFrameCallback* callback) {
John Recka5dda642014-05-22 15:43:54 -0700296 mPendingRegistrationFrameCallbacks.insert(callback);
John Recke45b1fd2014-04-15 09:50:16 -0700297}
298
John Reck01a5ea32014-12-03 13:01:07 -0800299bool RenderThread::removeFrameCallback(IFrameCallback* callback) {
300 size_t erased;
301 erased = mFrameCallbacks.erase(callback);
302 erased |= mPendingRegistrationFrameCallbacks.erase(callback);
303 return erased;
John Recka5dda642014-05-22 15:43:54 -0700304}
305
306void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
307 if (mFrameCallbacks.erase(callback)) {
308 mPendingRegistrationFrameCallbacks.insert(callback);
309 }
John Recke45b1fd2014-04-15 09:50:16 -0700310}
311
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400312sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) {
313 auto renderType = Properties::getRenderPipelineType();
314 switch (renderType) {
315 case RenderPipelineType::OpenGL:
316 return OpenGLPipeline::allocateHardwareBitmap(*this, skBitmap);
317 case RenderPipelineType::SkiaGL:
318 return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(*this, skBitmap);
319 case RenderPipelineType::SkiaVulkan:
320 return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap);
321 default:
John Reck1bcacfd2017-11-03 10:12:19 -0700322 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400323 break;
324 }
325 return nullptr;
326}
327
Stan Iliev6b894d72017-08-23 12:41:41 -0400328bool RenderThread::isCurrent() {
329 return gettid() == getInstance().getTid();
330}
331
John Reckcec24ae2013-11-05 13:27:50 -0800332} /* namespace renderthread */
333} /* namespace uirenderer */
334} /* namespace android */