/* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "RenderEngine" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include "GLESRenderEngine.h" #include "ImageManager.h" namespace android { namespace renderengine { namespace gl { ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) {} void ImageManager::initThread() { mThread = std::thread([this]() { threadMain(); }); pthread_setname_np(mThread.native_handle(), "ImageManager"); // Use SCHED_FIFO to minimize jitter struct sched_param param = {0}; param.sched_priority = 2; if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, ¶m) != 0) { ALOGE("Couldn't set SCHED_FIFO for ImageManager"); } } ImageManager::~ImageManager() { { std::lock_guard lock(mMutex); mRunning = false; } mCondition.notify_all(); if (mThread.joinable()) { mThread.join(); } } void ImageManager::cacheAsync(const sp& buffer, const std::shared_ptr& barrier) { if (buffer == nullptr) { { std::lock_guard lock(barrier->mutex); barrier->isOpen = true; barrier->result = BAD_VALUE; } barrier->condition.notify_one(); return; } ATRACE_CALL(); QueueEntry entry = {QueueEntry::Operation::Insert, buffer, buffer->getId(), barrier}; queueOperation(std::move(entry)); } status_t ImageManager::cache(const sp& buffer) { ATRACE_CALL(); auto barrier = std::make_shared(); cacheAsync(buffer, barrier); std::lock_guard lock(barrier->mutex); barrier->condition.wait(barrier->mutex, [&]() REQUIRES(barrier->mutex) { return barrier->isOpen; }); return barrier->result; } void ImageManager::releaseAsync(uint64_t bufferId, const std::shared_ptr& barrier) { ATRACE_CALL(); QueueEntry entry = {QueueEntry::Operation::Delete, nullptr, bufferId, barrier}; queueOperation(std::move(entry)); } void ImageManager::queueOperation(const QueueEntry&& entry) { { std::lock_guard lock(mMutex); mQueue.emplace(entry); ATRACE_INT("ImageManagerQueueDepth", mQueue.size()); } mCondition.notify_one(); } void ImageManager::threadMain() { set_sched_policy(0, SP_FOREGROUND); bool run; { std::lock_guard lock(mMutex); run = mRunning; } while (run) { QueueEntry entry; { std::lock_guard lock(mMutex); mCondition.wait(mMutex, [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; }); run = mRunning; if (!mRunning) { // if mRunning is false, then ImageManager is being destroyed, so // bail out now. break; } entry = mQueue.front(); mQueue.pop(); ATRACE_INT("ImageManagerQueueDepth", mQueue.size()); } status_t result = NO_ERROR; switch (entry.op) { case QueueEntry::Operation::Delete: mEngine->unbindExternalTextureBufferInternal(entry.bufferId); break; case QueueEntry::Operation::Insert: result = mEngine->cacheExternalTextureBufferInternal(entry.buffer); break; } if (entry.barrier != nullptr) { { std::lock_guard entryLock(entry.barrier->mutex); entry.barrier->result = result; entry.barrier->isOpen = true; } entry.barrier->condition.notify_one(); } } ALOGD("Reached end of threadMain, terminating ImageManager thread!"); } } // namespace gl } // namespace renderengine } // namespace android