diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 3813ee347..dab602ae7 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -76,6 +76,7 @@ target_link_libraries(${OLIVE_TARGET}
FFMPEG::swscale
FFMPEG::swresample
OpenColorIO
+ OpenImageIO
)
set(OLIVE_EFFECTS
diff --git a/app/common/define.h b/app/common/define.h
new file mode 100644
index 000000000..37ff4cc5d
--- /dev/null
+++ b/app/common/define.h
@@ -0,0 +1,26 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#ifndef OLIVECOMMONDEFINE_H
+#define OLIVECOMMONDEFINE_H
+
+const int kRGBAChannels = 4;
+
+#endif // OLIVECOMMONDEFINE_H
diff --git a/app/core.cpp b/app/core.cpp
index 9a12dd5c5..37ee31929 100644
--- a/app/core.cpp
+++ b/app/core.cpp
@@ -280,7 +280,8 @@ void Core::CreateNewSequence()
rp->SetParameters(new_sequence->video_width(),
new_sequence->video_height(),
olive::PIX_FMT_RGBA16F, // FIXME: Make this configurable
- olive::RenderMode::kOffline);
+ olive::RenderMode::kOffline,
+ 2);
// Set the "cache name" only here to aid the cache ID's uniqueness
rp->SetCacheName(new_sequence->name());
diff --git a/app/node/input/media/media.cpp b/app/node/input/media/media.cpp
index 9363e7d5c..f2d0981c0 100644
--- a/app/node/input/media/media.cpp
+++ b/app/node/input/media/media.cpp
@@ -223,9 +223,6 @@ QVariant MediaInput::Value(NodeOutput *output, const rational &time)
renderer->buffer()->Attach(output_texture);
renderer->buffer()->Bind();
- glClearColor(1.0, 0.0, 0.0, 1.0);
- glClear(GL_COLOR_BUFFER_BIT);
-
// Draw with the internal texture
internal_tex_.Bind();
diff --git a/app/node/processor/renderer/renderer.cpp b/app/node/processor/renderer/renderer.cpp
index 33eb536f6..e5b8f3cb4 100644
--- a/app/node/processor/renderer/renderer.cpp
+++ b/app/node/processor/renderer/renderer.cpp
@@ -20,6 +20,7 @@
#include "renderer.h"
+#include
#include
#include
#include
@@ -29,11 +30,13 @@
#include
#include "common/filefunctions.h"
+#include "render/pixelservice.h"
RendererProcessor::RendererProcessor() :
started_(false),
width_(0),
height_(0),
+ divider_(1),
caching_(false)
{
texture_input_ = new NodeInput("tex_in");
@@ -92,23 +95,21 @@ QVariant RendererProcessor::Value(NodeOutput* output, const rational& time)
return 0;
}
- // FIXME: Test code only
QString fn = CachePathName(time);
if (QFileInfo::exists(fn)) {
- QFile cache_img(fn);
+ auto in = OIIO::ImageInput::open(fn.toStdString());
- if (cache_img.open(QFile::ReadOnly)) {
+ if (in) {
+ in->read_image(PixelService::GetPixelFormatInfo(format_).oiio_desc, cache_frame_load_buffer_.data());
- QByteArray bytes = cache_img.readAll();
+ in->close();
- master_texture_->Upload(bytes.constData());
-
- cache_img.close();
+ master_texture_->Upload(cache_frame_load_buffer_.data());
return QVariant::fromValue(master_texture_);
}
+
}
- // End test code
}
return 0;
@@ -152,7 +153,8 @@ void RendererProcessor::SetTimebase(const rational &timebase)
void RendererProcessor::SetParameters(const int &width,
const int &height,
const olive::PixelFormat &format,
- const olive::RenderMode &mode)
+ const olive::RenderMode &mode,
+ const int& divider)
{
// Since we're changing parameters, all the existing threads are invalid and must be removed. They will start again
// next time this Node has to process anything.
@@ -164,6 +166,27 @@ void RendererProcessor::SetParameters(const int &width,
format_ = format;
mode_ = mode;
+ // divider's default value is 0, so we can assume if it's 0 a divider wasn't specified
+ if (divider > 0) {
+ divider_ = divider;
+ }
+
+ CalculateEffectiveDimensions();
+
+ // Regenerate the cache ID
+ GenerateCacheIDInternal();
+}
+
+void RendererProcessor::SetDivider(const int ÷r)
+{
+ Q_ASSERT(divider_ > 0);
+
+ Stop();
+
+ divider_ = divider;
+
+ CalculateEffectiveDimensions();
+
// Regenerate the cache ID
GenerateCacheIDInternal();
}
@@ -176,11 +199,13 @@ void RendererProcessor::Start()
QOpenGLContext* ctx = QOpenGLContext::currentContext();
- threads_.resize(QThread::idealThreadCount());
+ int background_thread_count = qMax(1, QThread::idealThreadCount() - 1);
+
+ threads_.resize(background_thread_count);
for (int i=0;i(ctx, width_, height_, format_, mode_);
- threads_[i]->StartThread(QThread::HighPriority);
+ threads_[i] = std::make_shared(ctx, effective_width_, effective_height_, format_, mode_);
+ threads_[i]->StartThread(QThread::LowPriority);
// Ensure this connection is "Queued" so that it always runs in this object's threaded rather than any of the
// other threads
@@ -188,13 +213,21 @@ void RendererProcessor::Start()
connect(threads_[i].get(), SIGNAL(RequestSibling(NodeDependency)), this, SLOT(ThreadRequestSibling(NodeDependency)), Qt::QueuedConnection);
}
- // Create download thread
- download_thread_ = std::make_shared(ctx, width_, height_, format_, mode_);
- download_thread_->StartThread(QThread::HighPriority);
+ download_threads_.resize(background_thread_count);
+
+ for (int i=0;i(ctx, effective_width_, effective_height_, format_, mode_);
+ download_threads_[i]->StartThread(QThread::LowPriority);
+ }
+
+ last_download_thread_ = 0;
// Create master texture (the one sent to the viewer)
master_texture_ = std::make_shared();
- master_texture_->Create(ctx, width_, height_, format_);
+ master_texture_->Create(ctx, effective_width_, effective_height_, format_);
+
+ cache_frame_load_buffer_.resize(PixelService::GetBufferSize(format_, effective_width_, effective_height_));
started_ = true;
}
@@ -212,15 +245,19 @@ void RendererProcessor::Stop()
}
threads_.clear();
- download_thread_->Cancel();
- download_thread_ = nullptr;
+ foreach (RendererDownloadThreadPtr download_thread_, download_threads_) {
+ download_thread_->Cancel();
+ }
+ download_threads_.clear();
master_texture_ = nullptr;
+
+ cache_frame_load_buffer_.clear();
}
void RendererProcessor::GenerateCacheIDInternal()
{
- if (cache_name_.isEmpty() || width_ == 0 || height_ == 0) {
+ if (cache_name_.isEmpty() || effective_width_ == 0 || effective_height_ == 0) {
return;
}
@@ -228,8 +265,8 @@ void RendererProcessor::GenerateCacheIDInternal()
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(cache_name_.toUtf8());
hash.addData(QString::number(cache_time_).toUtf8());
- hash.addData(QString::number(width_).toUtf8());
- hash.addData(QString::number(height_).toUtf8());
+ hash.addData(QString::number(effective_width_).toUtf8());
+ hash.addData(QString::number(effective_height_).toUtf8());
hash.addData(QString::number(format_).toUtf8());
QByteArray bytes = hash.result();
@@ -261,11 +298,17 @@ QString RendererProcessor::CachePathName(const rational &time)
QDir this_cache_dir = QDir(GetMediaCacheLocation()).filePath(cache_id_);
this_cache_dir.mkpath(".");
- QString filename = QString("%1.%2.jpg").arg(QString::number(time.numerator()), QString::number(time.denominator()));
+ QString filename = QString("%1.%2.exr").arg(QString::number(time.numerator()), QString::number(time.denominator()));
return this_cache_dir.filePath(filename);
}
+void RendererProcessor::CalculateEffectiveDimensions()
+{
+ effective_width_ = width_ / divider_;
+ effective_height_ = height_ / divider_;
+}
+
void RendererProcessor::ThreadCallback()
{
if (sender() == master_thread_) {
@@ -280,7 +323,9 @@ void RendererProcessor::ThreadCallback()
if (texture == nullptr && QFileInfo::exists(fn)) {
QFile(fn).remove();
} else {
- download_thread_->Queue(texture, fn);
+ // Choose download thread with the smallest queue
+ download_threads_[last_download_thread_%download_threads_.size()]->Queue(texture, fn);
+ last_download_thread_++;
}
CacheNext();
diff --git a/app/node/processor/renderer/renderer.h b/app/node/processor/renderer/renderer.h
index 1c0742d2c..8283b2043 100644
--- a/app/node/processor/renderer/renderer.h
+++ b/app/node/processor/renderer/renderer.h
@@ -78,7 +78,10 @@ public:
void SetParameters(const int& width,
const int& height,
const olive::PixelFormat& format,
- const olive::RenderMode& mode);
+ const olive::RenderMode& mode,
+ const int ÷r = 0);
+
+ void SetDivider(const int& divider);
/**
* @brief Return current instance of a RenderThread (or nullptr if there is none)
@@ -140,9 +143,14 @@ private:
NodeOutput* texture_output_;
int width_;
-
int height_;
+ void CalculateEffectiveDimensions();
+
+ int divider_;
+ int effective_width_;
+ int effective_height_;
+
olive::PixelFormat format_;
olive::RenderMode mode_;
@@ -158,8 +166,10 @@ private:
bool caching_;
RendererProcessThread* master_thread_;
rational cache_frame_;
+ QVector cache_frame_load_buffer_;
- RendererDownloadThreadPtr download_thread_;
+ QVector download_threads_;
+ int last_download_thread_;
RenderTexturePtr master_texture_;
diff --git a/app/node/processor/renderer/rendererdownloadthread.cpp b/app/node/processor/renderer/rendererdownloadthread.cpp
index 4c499b883..c0250f184 100644
--- a/app/node/processor/renderer/rendererdownloadthread.cpp
+++ b/app/node/processor/renderer/rendererdownloadthread.cpp
@@ -1,7 +1,9 @@
#include "rendererdownloadthread.h"
#include
+#include
+#include "common/define.h"
#include "render/pixelservice.h"
RendererDownloadThread::RendererDownloadThread(QOpenGLContext *share_ctx,
@@ -81,21 +83,31 @@ void RendererDownloadThread::ProcessLoop()
format_info.pixel_type,
data_buffer);
- render_instance()->context()->extraFunctions()->glFramebufferTexture2D(
- GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0
- );
+ xf->glFramebufferTexture2D(GL_READ_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ 0,
+ 0);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
- QFile data_dump(working_filename);
+ std::string working_fn_std = working_filename.toStdString();
- if (data_dump.open(QFile::WriteOnly)) {
- data_dump.write(reinterpret_cast(data_buffer), buffer_size);
+ std::unique_ptr out = OIIO::ImageOutput::create(working_fn_std);
- data_dump.close();
+ if (out) {
+ OIIO::ImageSpec spec(working_texture->width(), working_texture->height(), kRGBAChannels, format_info.oiio_desc);
+
+ spec.attribute("compression", "dwaa:200");
+
+ out->open(working_fn_std, spec);
+
+ out->write_image(format_info.oiio_desc, data_buffer);
+
+ out->close();
}
- qDebug() << "Saved" << working_filename;
+ qDebug() << this << "saved" << working_filename;
}
diff --git a/app/render/colorservice.cpp b/app/render/colorservice.cpp
index 533d60bd8..7c57fafd7 100644
--- a/app/render/colorservice.cpp
+++ b/app/render/colorservice.cpp
@@ -1,6 +1,6 @@
#include "colorservice.h"
-const int kRGBAChannels = 4;
+#include "common/define.h"
ColorService::ColorService(const char* source_space, const char* dest_space)
{
diff --git a/app/render/pixelservice.cpp b/app/render/pixelservice.cpp
index fc9815f83..babaf293f 100644
--- a/app/render/pixelservice.cpp
+++ b/app/render/pixelservice.cpp
@@ -24,7 +24,7 @@
#include
#include
-const int kRGBAChannels = 4;
+#include "common/define.h"
PixelService::PixelService()
{
@@ -39,21 +39,25 @@ PixelFormatInfo PixelService::GetPixelFormatInfo(const olive::PixelFormat &forma
info.name = tr("8-bit");
info.internal_format = GL_RGBA8;
info.pixel_type = GL_UNSIGNED_BYTE;
+ info.oiio_desc = OIIO::TypeDesc::UINT8;
break;
case olive::PIX_FMT_RGBA16:
info.name = tr("16-bit Integer");
info.internal_format = GL_RGBA16;
info.pixel_type = GL_UNSIGNED_SHORT;
+ info.oiio_desc = OIIO::TypeDesc::UINT16;
break;
case olive::PIX_FMT_RGBA16F:
info.name = tr("Half-Float (16-bit)");
info.internal_format = GL_RGBA16F;
info.pixel_type = GL_HALF_FLOAT;
+ info.oiio_desc = OIIO::TypeDesc::HALF;
break;
case olive::PIX_FMT_RGBA32F:
info.name = tr("Full-Float (32-bit)");
info.internal_format = GL_RGBA32F;
info.pixel_type = GL_FLOAT;
+ info.oiio_desc = OIIO::TypeDesc::FLOAT;
break;
default:
qFatal("Invalid pixel format requested");
diff --git a/app/render/pixelservice.h b/app/render/pixelservice.h
index cc41f1f1f..6cb0f5102 100644
--- a/app/render/pixelservice.h
+++ b/app/render/pixelservice.h
@@ -23,6 +23,7 @@
#include
#include
+#include
#include "decoder/frame.h"
#include "pixelformat.h"
@@ -43,6 +44,7 @@ struct PixelFormatInfo {
GLenum pixel_format;
GLenum pixel_type;
int bytes_per_pixel;
+ OIIO::TypeDesc oiio_desc;
};
class PixelService : public QObject {
diff --git a/app/render/renderinstance.h b/app/render/renderinstance.h
index e61372752..0d6c47a6d 100644
--- a/app/render/renderinstance.h
+++ b/app/render/renderinstance.h
@@ -79,6 +79,8 @@ private:
olive::PixelFormat format_;
olive::RenderMode mode_;
+
+ int divider_;
};
#endif // GLINSTANCE_H