blob: 62566494f0053e864ef4c9df9f8d6f96654dc9a4 [file] [log] [blame]
/*
* 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 <pthread.h>
#include <processgroup/sched_policy.h>
#include <utils/Trace.h>
#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, &param) != 0) {
ALOGE("Couldn't set SCHED_FIFO for ImageManager");
}
}
ImageManager::~ImageManager() {
{
std::lock_guard<std::mutex> lock(mMutex);
mRunning = false;
}
mCondition.notify_all();
if (mThread.joinable()) {
mThread.join();
}
}
void ImageManager::cacheAsync(const sp<GraphicBuffer>& buffer,
const std::shared_ptr<Barrier>& barrier) {
if (buffer == nullptr) {
{
std::lock_guard<std::mutex> 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<GraphicBuffer>& buffer) {
ATRACE_CALL();
auto barrier = std::make_shared<Barrier>();
cacheAsync(buffer, barrier);
std::lock_guard<std::mutex> 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>& barrier) {
ATRACE_CALL();
QueueEntry entry = {QueueEntry::Operation::Delete, nullptr, bufferId, barrier};
queueOperation(std::move(entry));
}
void ImageManager::queueOperation(const QueueEntry&& entry) {
{
std::lock_guard<std::mutex> 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<std::mutex> lock(mMutex);
run = mRunning;
}
while (run) {
QueueEntry entry;
{
std::lock_guard<std::mutex> 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<std::mutex> 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