attempt to merge separate processors into one

Previous iteration used probably an excessive amount of threads to make
everything work. New iteration intends to use precisely the amount of logical
threads available and using a moved QObject rather than a subclassed QThread
This commit is contained in:
itsmattkc
2019-10-31 23:27:20 +11:00
parent b56fbaae51
commit f13fb648c7
8 changed files with 169 additions and 434 deletions
+131 -26
View File
@@ -21,8 +21,13 @@
#include "videorendererthreadbase.h"
#include <QDebug>
#include <QThread>
VideoRendererThreadBase::VideoRendererThreadBase(QOpenGLContext *share_ctx, const VideoRenderingParams &params) :
#include "common/define.h"
#include "videorenderbackend.h"
VideoRendererThreadBase::VideoRendererThreadBase(VideoRenderBackend* parent, QOpenGLContext *share_ctx, const VideoRenderingParams &params) :
parent_(parent),
share_ctx_(share_ctx),
render_instance_(params)
{
@@ -34,50 +39,150 @@ RenderInstance *VideoRendererThreadBase::render_instance()
return &render_instance_;
}
void VideoRendererThreadBase::run()
void VideoRendererThreadBase::Start()
{
// Lock mutex for main loop
mutex_.lock();
render_instance_.SetShareContext(share_ctx_);
// Allocate and create resources
bool started = render_instance_.Start();
render_instance_.Start();
// Signal that main thread can continue now
WakeCaller();
if (started) {
// Set up download functions
f = render_instance()->context()->functions();
xf = render_instance()->context()->extraFunctions();
// Main loop (use Cancel() to exit it)
ProcessLoop();
f->glGenFramebuffers(1, &read_buffer_);
}
int buffer_size = PixelService::GetBufferSize(render_instance()->params().format(),
render_instance()->params().width(),
render_instance()->params().height());
data_buffer_.resize(buffer_size);
format_info_ = PixelService::GetPixelFormatInfo(render_instance()->params().format());
// Set up OIIO::ImageSpec for compressing cached images on disk
spec_ = OIIO::ImageSpec(render_instance()->params().width(), render_instance()->params().height(), kRGBAChannels, format_info_.oiio_desc);
spec_.attribute("compression", "dwaa:200");
}
void VideoRendererThreadBase::Stop()
{
f->glDeleteFramebuffers(1, &read_buffer_);
// Free all resources
render_instance_.Stop();
// Unlock mutex before exiting
mutex_.unlock();
thread()->quit();
}
void VideoRendererThreadBase::WakeCaller()
void VideoRendererThreadBase::Process(const NodeDependency &path, bool sibling)
{
// Signal that main thread can continue now
caller_mutex_.lock();
wait_cond_.wakeAll();
caller_mutex_.unlock();
// Process the Node
NodeOutput* output_to_process = path.node();
Node* node_to_process = output_to_process->parent();
texture_ = nullptr;
QList<Node*> all_deps;
bool has_hash = false;
bool can_cache = true;
QByteArray hash;
if (!sibling) {
node_to_process->Lock();
all_deps = node_to_process->GetDependencies();
foreach (Node* dep, all_deps) {
dep->Lock();
}
// Check hash
QCryptographicHash hasher(QCryptographicHash::Sha1);
node_to_process->Hash(&hasher, output_to_process, path.in());
hash = hasher.result();
has_hash = parent_->HasHash(hash);
can_cache = false;
}
if (!has_hash){
if ((can_cache = parent_->TryCache(hash))) {
QList<NodeDependency> deps = node_to_process->RunDependencies(output_to_process, path.in());
// Ask for other threads to run these deps while we're here
if (!deps.isEmpty()) {
for (int i=1;i<deps.size();i++) {
emit RequestSibling(deps.at(i));
}
}
// Get the requested value
texture_ = output_to_process->get_value(path.in(), path.in()).value<RenderTexturePtr>();
render_instance()->context()->functions()->glFinish();
}
}
if (!sibling) {
foreach (Node* dep, all_deps) {
dep->Unlock();
}
node_to_process->Unlock();
}
if (can_cache) {
// We cached this frame, signal that it will need to be downloaded to disk
emit CachedFrame(texture_, path.in(), hash);
} else {
// This hash already exists, no need to cache, just map it
emit FrameSkipped(path.in(), hash);
}
}
void VideoRendererThreadBase::StartThread(QThread::Priority priority)
void VideoRendererThreadBase::Download(RenderTexturePtr texture, const QString &fn, const QByteArray &hash)
{
caller_mutex_.lock();
// Download the texture
// Start the thread
QThread::start(priority);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, read_buffer_);
// Wait for thread to finish completion
wait_cond_.wait(&caller_mutex_);
xf->glFramebufferTexture2D(GL_READ_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
texture->texture(),
0);
caller_mutex_.unlock();
f->glReadPixels(0,
0,
texture->width(),
texture->height(),
format_info_.pixel_format,
format_info_.gl_pixel_type,
data_buffer_.data());
xf->glFramebufferTexture2D(GL_READ_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
0,
0);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
std::string working_fn_std = fn.toStdString();
std::unique_ptr<OIIO::ImageOutput> out = OIIO::ImageOutput::create(working_fn_std);
if (out) {
out->open(working_fn_std, spec_);
out->write_image(format_info_.oiio_desc, data_buffer_.data());
out->close();
emit Downloaded(hash);
} else {
qWarning() << QStringLiteral("Failed to open output file \"%1\"").arg(fn);
}
}