diff options
Diffstat (limited to 'libs/hwui/renderthread/RenderThread.cpp')
-rw-r--r-- | libs/hwui/renderthread/RenderThread.cpp | 284 |
1 files changed, 57 insertions, 227 deletions
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 72a428f1c70c..79dc09ffbf1d 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -16,17 +16,17 @@ #include "RenderThread.h" -#include "hwui/Bitmap.h" -#include "renderstate/RenderState.h" -#include "renderthread/OpenGLPipeline.h" -#include "pipeline/skia/SkiaOpenGLReadback.h" -#include "pipeline/skia/SkiaOpenGLPipeline.h" -#include "pipeline/skia/SkiaVulkanPipeline.h" #include "CanvasContext.h" #include "EglManager.h" #include "OpenGLReadback.h" #include "RenderProxy.h" #include "VulkanManager.h" +#include "hwui/Bitmap.h" +#include "pipeline/skia/SkiaOpenGLPipeline.h" +#include "pipeline/skia/SkiaOpenGLReadback.h" +#include "pipeline/skia/SkiaVulkanPipeline.h" +#include "renderstate/RenderState.h" +#include "renderthread/OpenGLPipeline.h" #include "utils/FatVector.h" #include <gui/DisplayEventReceiver.h> @@ -49,107 +49,19 @@ static const size_t EVENT_BUFFER_SIZE = 100; // Slight delay to give the UI time to push us a new frame before we replay static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4); -TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {} - -RenderTask* TaskQueue::next() { - RenderTask* ret = mHead; - if (ret) { - mHead = ret->mNext; - if (!mHead) { - mTail = nullptr; - } - ret->mNext = nullptr; - } - return ret; -} - -RenderTask* TaskQueue::peek() { - return mHead; -} - -void TaskQueue::queue(RenderTask* task) { - // Since the RenderTask itself forms the linked list it is not allowed - // to have the same task queued twice - LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!"); - if (mTail) { - // Fast path if we can just append - if (mTail->mRunAt <= task->mRunAt) { - mTail->mNext = task; - mTail = task; - } else { - // Need to find the proper insertion point - RenderTask* previous = nullptr; - RenderTask* next = mHead; - while (next && next->mRunAt <= task->mRunAt) { - previous = next; - next = next->mNext; - } - if (!previous) { - task->mNext = mHead; - mHead = task; - } else { - previous->mNext = task; - if (next) { - task->mNext = next; - } else { - mTail = task; - } - } - } - } else { - mTail = mHead = task; - } -} - -void TaskQueue::queueAtFront(RenderTask* task) { - LOG_ALWAYS_FATAL_IF(task->mNext || mHead == task, "Task is already in the queue!"); - if (mTail) { - task->mNext = mHead; - mHead = task; - } else { - mTail = mHead = task; - } -} - -void TaskQueue::remove(RenderTask* task) { - // TaskQueue is strict here to enforce that users are keeping track of - // their RenderTasks due to how their memory is managed - LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task, - "Cannot remove a task that isn't in the queue!"); - - // If task is the head we can just call next() to pop it off - // Otherwise we need to scan through to find the task before it - if (peek() == task) { - next(); - } else { - RenderTask* previous = mHead; - while (previous->mNext != task) { - previous = previous->mNext; - } - previous->mNext = task->mNext; - if (mTail == task) { - mTail = previous; - } - } -} - -class DispatchFrameCallbacks : public RenderTask { -private: - RenderThread* mRenderThread; -public: - explicit DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {} - - virtual void run() override { - mRenderThread->dispatchFrameCallbacks(); - } -}; - static bool gHasRenderThreadInstance = false; +static void (*gOnStartHook)() = nullptr; + bool RenderThread::hasInstance() { return gHasRenderThreadInstance; } +void RenderThread::setOnStartHook(void (*onStartHook)()) { + LOG_ALWAYS_FATAL_IF(hasInstance(), "can't set an onStartHook after we've started..."); + gOnStartHook = onStartHook; +} + RenderThread& RenderThread::getInstance() { // This is a pointer because otherwise __cxa_finalize // will try to delete it like a Good Citizen but that causes us to crash @@ -159,19 +71,16 @@ RenderThread& RenderThread::getInstance() { return *sInstance; } -RenderThread::RenderThread() : Thread(true) - , mNextWakeup(LLONG_MAX) +RenderThread::RenderThread() + : ThreadBase() , mDisplayEventReceiver(nullptr) , mVsyncRequested(false) , mFrameCallbackTaskPending(false) - , mFrameCallbackTask(nullptr) , mRenderState(nullptr) , mEglManager(nullptr) , mVkManager(nullptr) { Properties::load(); - mFrameCallbackTask = new DispatchFrameCallbacks(this); - mLooper = new Looper(false); - run("RenderThread"); + start("RenderThread"); } RenderThread::~RenderThread() { @@ -182,17 +91,18 @@ void RenderThread::initializeDisplayEventReceiver() { LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?"); mDisplayEventReceiver = new DisplayEventReceiver(); status_t status = mDisplayEventReceiver->initCheck(); - LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver " - "failed with status: %d", status); + LOG_ALWAYS_FATAL_IF(status != NO_ERROR, + "Initialization of DisplayEventReceiver " + "failed with status: %d", + status); // Register the FD - mLooper->addFd(mDisplayEventReceiver->getFd(), 0, - Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this); + mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT, + RenderThread::displayEventReceiverCallback, this); } void RenderThread::initThreadLocals() { - sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay( - ISurfaceComposer::eDisplayIdMain)); + sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo); LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n"); nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps); @@ -232,18 +142,15 @@ void RenderThread::dumpGraphicsMemory(int fd) { break; } default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } - FILE *file = fdopen(fd, "a"); - fprintf(file, "\n%s\n", cachesOutput.string()); - fprintf(file, "\nPipeline=%s\n", pipeline.string()); - fflush(file); + dprintf(fd, "\n%s\n", cachesOutput.string()); + dprintf(fd, "\nPipeline=%s\n", pipeline.string()); } Readback& RenderThread::readback() { - if (!mReadback) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { @@ -258,7 +165,7 @@ Readback& RenderThread::readback() { mReadback = new skiapipeline::SkiaOpenGLReadback(*this); break; default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } } @@ -266,30 +173,32 @@ Readback& RenderThread::readback() { return *mReadback; } -void RenderThread::setGrContext(GrContext* context) { +void RenderThread::setGrContext(sk_sp<GrContext> context) { mCacheManager->reset(context); - if (mGrContext.get()) { + if (mGrContext) { mGrContext->releaseResourcesAndAbandonContext(); } - mGrContext.reset(context); + mGrContext = std::move(context); } int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) { if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { ALOGE("Display event receiver pipe was closed or an error occurred. " - "events=0x%x", events); - return 0; // remove the callback + "events=0x%x", + events); + return 0; // remove the callback } if (!(events & Looper::EVENT_INPUT)) { ALOGW("Received spurious callback for unhandled poll event. " - "events=0x%x", events); - return 1; // keep the callback + "events=0x%x", + events); + return 1; // keep the callback } reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue(); - return 1; // keep the callback + return 1; // keep the callback } static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) { @@ -300,9 +209,9 @@ static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) { for (ssize_t i = 0; i < n; i++) { const DisplayEventReceiver::Event& ev = buf[i]; switch (ev.header.type) { - case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: - latest = ev.header.timestamp; - break; + case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: + latest = ev.header.timestamp; + break; } } } @@ -321,7 +230,7 @@ void RenderThread::drainDisplayEventQueue() { ATRACE_NAME("queue mFrameCallbackTask"); mFrameCallbackTaskPending = true; nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY); - queueAt(mFrameCallbackTask, runAt); + queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); }); } } } @@ -337,7 +246,8 @@ void RenderThread::dispatchFrameCallbacks() { // Assume one of them will probably animate again so preemptively // request the next vsync in case it occurs mid-frame requestVsync(); - for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) { + for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); + it++) { (*it)->doFrame(); } } @@ -347,49 +257,25 @@ void RenderThread::requestVsync() { if (!mVsyncRequested) { mVsyncRequested = true; status_t status = mDisplayEventReceiver->requestNextVsync(); - LOG_ALWAYS_FATAL_IF(status != NO_ERROR, - "requestNextVsync failed with status: %d", status); + LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "requestNextVsync failed with status: %d", status); } } bool RenderThread::threadLoop() { setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY); + if (gOnStartHook) { + gOnStartHook(); + } initThreadLocals(); - int timeoutMillis = -1; - for (;;) { - int result = mLooper->pollOnce(timeoutMillis); - LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, - "RenderThread Looper POLL_ERROR!"); - - nsecs_t nextWakeup; - { - FatVector<RenderTask*, 10> workQueue; - // Process our queue, if we have anything. By first acquiring - // all the pending events then processing them we avoid vsync - // starvation if more tasks are queued while we are processing tasks. - while (RenderTask* task = nextTask(&nextWakeup)) { - workQueue.push_back(task); - } - for (auto task : workQueue) { - task->run(); - // task may have deleted itself, do not reference it again - } - } - if (nextWakeup == LLONG_MAX) { - timeoutMillis = -1; - } else { - nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC); - timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos); - if (timeoutMillis < 0) { - timeoutMillis = 0; - } - } + while (true) { + waitForWork(); + processQueue(); if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) { drainDisplayEventQueue(); - mFrameCallbacks.insert( - mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end()); + mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(), + mPendingRegistrationFrameCallbacks.end()); mPendingRegistrationFrameCallbacks.clear(); requestVsync(); } @@ -406,46 +292,6 @@ bool RenderThread::threadLoop() { return false; } -void RenderThread::queue(RenderTask* task) { - AutoMutex _lock(mLock); - mQueue.queue(task); - if (mNextWakeup && task->mRunAt < mNextWakeup) { - mNextWakeup = 0; - mLooper->wake(); - } -} - -void RenderThread::queueAndWait(RenderTask* task) { - // These need to be local to the thread to avoid the Condition - // signaling the wrong thread. The easiest way to achieve that is to just - // make this on the stack, although that has a slight cost to it - Mutex mutex; - Condition condition; - SignalingRenderTask syncTask(task, &mutex, &condition); - - AutoMutex _lock(mutex); - queue(&syncTask); - while (!syncTask.hasRun()) { - condition.wait(mutex); - } -} - -void RenderThread::queueAtFront(RenderTask* task) { - AutoMutex _lock(mLock); - mQueue.queueAtFront(task); - mLooper->wake(); -} - -void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) { - task->mRunAt = runAtNs; - queue(task); -} - -void RenderThread::remove(RenderTask* task) { - AutoMutex _lock(mLock); - mQueue.remove(task); -} - void RenderThread::postFrameCallback(IFrameCallback* callback) { mPendingRegistrationFrameCallbacks.insert(callback); } @@ -463,26 +309,6 @@ void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { } } -RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { - AutoMutex _lock(mLock); - RenderTask* next = mQueue.peek(); - if (!next) { - mNextWakeup = LLONG_MAX; - } else { - mNextWakeup = next->mRunAt; - // Most tasks won't be delayed, so avoid unnecessary systemTime() calls - if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) { - next = mQueue.next(); - } else { - next = nullptr; - } - } - if (nextWakeup) { - *nextWakeup = mNextWakeup; - } - return next; -} - sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { @@ -493,12 +319,16 @@ sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) { case RenderPipelineType::SkiaVulkan: return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap); default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } return nullptr; } +bool RenderThread::isCurrent() { + return gettid() == getInstance().getTid(); +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ |