media node upgrades to reference pixel format

This commit is contained in:
itsmattkc
2019-08-29 12:30:42 +10:00
parent 7dc2290496
commit deff114241
21 changed files with 574 additions and 197 deletions
+12
View File
@@ -61,3 +61,15 @@ QString GetMediaIndexFilename(const QString &filename)
{
return QDir(GetMediaIndexLocation()).filePath(filename);
}
QString GetMediaCacheLocation()
{
QDir local_appdata_dir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
QDir media_cache_dir = local_appdata_dir.filePath("mediacache");
// Attempt to ensure this folder exists
media_cache_dir.mkpath(".");
return media_cache_dir.absolutePath();
}
+2
View File
@@ -29,4 +29,6 @@ QString GetMediaIndexLocation();
QString GetMediaIndexFilename(const QString& filename);
QString GetMediaCacheLocation();
#endif // FILEFUNCTIONS_H
+107 -28
View File
@@ -34,8 +34,10 @@
// End test code
MediaInput::MediaInput() :
//ocio_shader_(nullptr),
decoder_(nullptr)
decoder_(nullptr),
color_service_(nullptr),
pipeline_(nullptr),
ocio_texture_(0)
{
footage_input_ = new NodeInput("footage_in");
footage_input_->add_data_input(NodeInput::kFootage);
@@ -72,9 +74,20 @@ QString MediaInput::Description()
void MediaInput::Release()
{
texture_.Destroy();
internal_tex_.Destroy();
decoder_ = nullptr;
color_service_ = nullptr;
pipeline_ = nullptr;
if (ocio_texture_ != 0) {
ocio_ctx_->functions()->glDeleteTextures(1, &ocio_texture_);
}
}
NodeInput *MediaInput::matrix_input()
{
return matrix_input_;
}
NodeOutput *MediaInput::texture_output()
@@ -89,6 +102,8 @@ void MediaInput::SetFootage(Footage *f)
QVariant MediaInput::Value(NodeOutput *output, const rational &time)
{
bool alpha_is_associated = false;
if (output == texture_output_) {
// Find the current Renderer instance
RenderInstance* renderer = RendererProcessor::CurrentInstance();
@@ -126,42 +141,106 @@ QVariant MediaInput::Value(NodeOutput *output, const rational &time)
return 0;
}
RenderTexturePtr texture = std::make_shared<RenderTexture>();
if (color_service_ == nullptr) {
// FIXME: Hardcoded values for texting
color_service_ = std::make_shared<ColorService>("srgb", OCIO::ROLE_SCENE_LINEAR);
}
texture->Create(renderer->context(),
// OpenColorIO v1's color transforms can be done on GPU, which improves performance but reduces accuracy. When
// online, we prefer accuracy over performance so we use the CPU path instead:
// NOTE: OCIO v2 boasts 1:1 results with the CPU and GPU path so this won't be necessary forever
if (renderer->mode() == olive::RenderMode::kOnline) {
// Convert to 32F, which is required for OpenColorIO's color transformation
frame = PixelService::ConvertPixelFormat(frame, olive::PIX_FMT_RGBA32F);
if (alpha_is_associated) {
// FIXME: Unassociate alpha here if associated
}
// Transform color to reference space
color_service_->ConvertFrame(frame);
if (alpha_is_associated) {
// FIXME: Reassociate alpha here
} else {
// FIXME: Associate alpha here
}
}
// We use an internal texture to bring the texture into GPU space before performing transformations
// Ensure the texture is the accurate to the frame
if (internal_tex_.width() != frame->width()
|| internal_tex_.height() != frame->height()
|| internal_tex_.format() != frame->format()) {
internal_tex_.Destroy();
}
// Create or upload the new data to the texture
if (!internal_tex_.IsCreated()) {
internal_tex_.Create(renderer->context(),
frame->width(),
frame->height(),
static_cast<olive::PixelFormat>(frame->format()),
frame->data());
} else {
internal_tex_.Upload(frame->data());
}
// Create new texture in reference space to send throughout the rest of the graph
RenderTexturePtr output_texture = std::make_shared<RenderTexture>();
output_texture->Create(renderer->context(),
renderer->width(),
renderer->height(),
static_cast<olive::PixelFormat>(frame->format()),
frame->data());
renderer->format(),
RenderTexture::kDoubleBuffer);
return QVariant::fromValue(texture);
// Using the transformation matrix, blit our internal texture (in frame format) to our output texture (in
// reference format)
/*renderer->buffer()->Upload(frame->data());
if (renderer->mode() == olive::RenderMode::kOffline) {
// For offline rendering, OCIO's GPU path is acceptable:
// NOTE: OCIO v2 boasts 1:1 results with the CPU and GPU path so this won't be necessary forever
texture_output_->set_value(renderer->buffer()->texture());*/
// Use an OCIO pipeline shader (which wraps in a default pipeline and will also handle alpha association)
if (pipeline_ == nullptr) {
/*pipeline_ = olive::ShaderGenerator::OCIOPipeline(renderer->context(),
ocio_texture_, // FIXME: A raw GLuint texture, should wrap this up
color_service_->GetProcessor(),
alpha_is_associated);
// Convert the frame to the Renderer format
// frame = PixelService::ConvertPixelFormat(frame, olive::PIX_FMT_RGBA16F);
// Used for cleanup later
ocio_ctx_ = renderer->context();*/
// Convert the frame to the Renderer color space
//color_service_.ConvertFrame(frame);
pipeline_ = olive::ShaderGenerator::DefaultPipeline();
}
} else if (pipeline_ == nullptr) {
// In online, the color transformation was performed on the CPU (see above), so we only need to blit
pipeline_ = olive::ShaderGenerator::DefaultPipeline();
}
// Upload this frame to the GPU
/*if (buffer_.IsCreated()) {
buffer_.Upload(frame->data());
} else {
buffer_.Create(QOpenGLContext::currentContext(),
static_cast<olive::PixelFormat>(frame->format()),
frame->width(),
frame->height(),
frame->data());
}*/
// Draw onto the output texture using the renderer's framebuffer
renderer->buffer()->Attach(output_texture);
renderer->buffer()->Bind();
// Draw according to matrix
// BLIT
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
//texture_output_->set_value(tex_buf_.texture());
// End test code
// Draw with the internal texture
internal_tex_.Bind();
// Use pipeline to blit using transformation matrix from input
QMatrix4x4 m;
olive::gl::Blit(pipeline_, false);
// Release everything
internal_tex_.Release();
renderer->buffer()->Detach();
renderer->buffer()->Release();
return QVariant::fromValue(output_texture);
}
return 0;
+10 -6
View File
@@ -26,11 +26,8 @@
#include "decoder/decoder.h"
#include "node/node.h"
#include "render/colorservice.h"
// FIXME: Test code only
#include "render/rendertexture.h"
#include "render/gl/shaderptr.h"
// End test code
#include "render/gl/shadergenerators.h"
/**
* @brief A node that imports an image
@@ -48,6 +45,8 @@ public:
virtual void Release() override;
NodeInput* matrix_input();
NodeOutput* texture_output();
void SetFootage(Footage* f);
@@ -62,11 +61,16 @@ private:
NodeOutput* texture_output_;
RenderTexture texture_;
RenderTexture internal_tex_;
DecoderPtr decoder_;
ColorService color_service_;
ColorServicePtr color_service_;
ShaderPtr pipeline_;
QOpenGLContext* ocio_ctx_;
GLuint ocio_texture_;
};
+2
View File
@@ -108,6 +108,8 @@ void ViewerOutput::ViewerTimeChanged(const rational &t)
// Send the texture to the Viewer
if (current_texture != nullptr) {
attached_viewer_->SetTexture(current_texture->texture());
} else {
attached_viewer_->SetTexture(0);
}
current_time_ = t;
+6 -2
View File
@@ -18,7 +18,11 @@ set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/processor/renderer/renderer.h
node/processor/renderer/renderer.cpp
node/processor/renderer/rendererthread.h
node/processor/renderer/rendererthread.cpp
node/processor/renderer/rendererthreadbase.h
node/processor/renderer/rendererthreadbase.cpp
node/processor/renderer/rendererdownloadthread.h
node/processor/renderer/rendererdownloadthread.cpp
node/processor/renderer/rendererprocessthread.h
node/processor/renderer/rendererprocessthread.cpp
PARENT_SCOPE
)
+67 -60
View File
@@ -24,9 +24,12 @@
#include <QCryptographicHash>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QImage>
#include <QtMath>
#include "common/filefunctions.h"
RendererProcessor::RendererProcessor() :
started_(false),
width_(0),
@@ -70,6 +73,7 @@ void RendererProcessor::SetCacheName(const QString &s)
GenerateCacheIDInternal();
}
#include <QFileInfo>
QVariant RendererProcessor::Value(NodeOutput* output, const rational& time)
{
if (output == texture_output_) {
@@ -89,55 +93,25 @@ QVariant RendererProcessor::Value(NodeOutput* output, const rational& time)
}
// FIXME: Test code only
return texture_input_->get_value(time);
QString fn = CachePathName(time);
if (QFileInfo::exists(fn)) {
QFile cache_img(fn);
if (cache_img.open(QFile::ReadOnly)) {
QByteArray bytes = cache_img.readAll();
master_texture_->Upload(bytes.constData());
cache_img.close();
return QVariant::fromValue(master_texture_);
}
}
// End test code
}
return 0;
// This Renderer node relies on a disk cache so this Process() function should be quite fast. Either it returns the
// cached frame or it returns nothing.
// Perhaps it should lookahead to load textures into VRAM in advance?
// Should it cache the final result or the result in an 8-bit image or a 16-bit intermediate image?
/*qDebug() << QString("Requesting %1/%2").arg(QString::number(time.numerator()), QString::number(time.denominator()));
if (cache_map_.contains(time)) {
qDebug() << " We have this frame!";
} else {
qDebug() << " No frame at this address";
cache_map_.insert(time, true);
}*/
// FIXME: Test code only
//GLuint tex = texture_input_->get_value(time).value<GLuint>();
//glReadPixels()
//texture_output_->set_value(tex);
// End test code
/*
// Ensure we have started
if (!started_) {
Start();
if (!started_) {
qWarning() << tr("An error occurred starting the Renderer node");
return;
}
}
*/
}
void RendererProcessor::Release()
@@ -152,9 +126,13 @@ void RendererProcessor::InvalidateCache(const rational &start_range, const ratio
<< "and"
<< end_range.toDouble();
// FIXME: Snap start_range to timebase
// Snap start_range to timebase
double start_range_dbl = start_range.toDouble();
double start_range_numf = start_range_dbl * static_cast<double>(timebase_.denominator());
int64_t start_range_numround = qFloor(start_range_numf/static_cast<double>(timebase_.numerator())) * timebase_.numerator();
rational true_start_range(start_range_numround, timebase_.denominator());
for (rational r=start_range;r<=end_range;r+=timebase_) {
for (rational r=true_start_range;r<=end_range;r+=timebase_) {
if (!cache_queue_.contains(r)) {
cache_queue_.append(r);
}
@@ -196,10 +174,12 @@ void RendererProcessor::Start()
return;
}
QOpenGLContext* ctx = QOpenGLContext::currentContext();
threads_.resize(QThread::idealThreadCount());
for (int i=0;i<threads_.size();i++) {
threads_[i] = std::make_shared<RendererThread>(QOpenGLContext::currentContext(), width_, height_, format_, mode_);
threads_[i] = std::make_shared<RendererProcessThread>(ctx, width_, height_, format_, mode_);
threads_[i]->StartThread(QThread::HighPriority);
// Ensure this connection is "Queued" so that it always runs in this object's threaded rather than any of the
@@ -208,6 +188,14 @@ void RendererProcessor::Start()
connect(threads_[i].get(), SIGNAL(RequestSibling(NodeDependency)), this, SLOT(ThreadRequestSibling(NodeDependency)), Qt::QueuedConnection);
}
// Create download thread
download_thread_ = std::make_shared<RendererDownloadThread>(ctx, width_, height_, format_, mode_);
download_thread_->StartThread(QThread::HighPriority);
// Create master texture (the one sent to the viewer)
master_texture_ = std::make_shared<RenderTexture>();
master_texture_->Create(ctx, width_, height_, format_);
started_ = true;
}
@@ -219,11 +207,15 @@ void RendererProcessor::Stop()
started_ = false;
for (int i=0;i<threads_.size();i++) {
threads_[i]->Cancel();
foreach (RendererProcessThreadPtr process_thread, threads_) {
process_thread->Cancel();
}
threads_.clear();
download_thread_->Cancel();
download_thread_ = nullptr;
master_texture_ = nullptr;
}
void RendererProcessor::GenerateCacheIDInternal()
@@ -253,20 +245,26 @@ void RendererProcessor::CacheNext()
// Make sure cache has started
Start();
rational time_to_cache = cache_queue_.takeFirst();
cache_frame_ = cache_queue_.takeFirst();
qDebug() << "Caching" << time_to_cache.toDouble();
qDebug() << "[RendererProcessor] Caching" << cache_frame_.toDouble();
// Run this probe in another thread
master_thread_ = threads_.at(0).get();
master_thread_->Queue(NodeDependency(texture_input_->get_connected_output(), time_to_cache), true);
master_thread_->Queue(NodeDependency(texture_input_->get_connected_output(), cache_frame_), true);
caching_ = true;
}
// FIXME: Test code only
#include "node/output/viewer/viewer.h"
// End test code
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()));
return this_cache_dir.filePath(filename);
}
void RendererProcessor::ThreadCallback()
{
@@ -275,6 +273,15 @@ void RendererProcessor::ThreadCallback()
caching_ = false;
// FIXME: Save the texture results here
RenderTexturePtr texture = texture_input_->get_value(cache_frame_).value<RenderTexturePtr>();
QString fn = CachePathName(cache_frame_);
if (texture == nullptr && QFileInfo::exists(fn)) {
QFile(fn).remove();
} else {
download_thread_->Queue(texture, fn);
}
CacheNext();
}
@@ -290,14 +297,14 @@ void RendererProcessor::ThreadRequestSibling(NodeDependency dep)
}
}
RendererThread* RendererProcessor::CurrentThread()
RendererThreadBase* RendererProcessor::CurrentThread()
{
return dynamic_cast<RendererThread*>(QThread::currentThread());
return dynamic_cast<RendererThreadBase*>(QThread::currentThread());
}
RenderInstance *RendererProcessor::CurrentInstance()
{
RendererThread* thread = CurrentThread();
RendererThreadBase* thread = CurrentThread();
if (thread != nullptr) {
return thread->render_instance();
+17 -5
View File
@@ -26,7 +26,8 @@
#include "node/node.h"
#include "render/pixelformat.h"
#include "render/rendermodes.h"
#include "rendererthread.h"
#include "rendererdownloadthread.h"
#include "rendererprocessthread.h"
/**
* @brief A multithreaded OpenGL based renderer for node systems
@@ -85,7 +86,7 @@ public:
* This function attempts a dynamic_cast on QThread::currentThread() to RendererThread, which will return nullptr if
* the cast fails (e.g. if this function is called from the main thread rather than a RendererThread).
*/
static RendererThread* CurrentThread();
static RendererThreadBase* CurrentThread();
static RenderInstance* CurrentInstance();
@@ -120,9 +121,14 @@ private:
void CacheNext();
/**
* @brief Internal list of RenderThreads
* @brief Return the path of the cached image at this time
*/
QVector<RendererThreadPtr> threads_;
QString CachePathName(const rational& time);
/**
* @brief Internal list of RenderProcessThreads
*/
QVector<RendererProcessThreadPtr> threads_;
/**
* @brief Internal variable that contains whether the Renderer has started or not
@@ -148,8 +154,14 @@ private:
QString cache_name_;
qint64 cache_time_;
QString cache_id_;
bool caching_;
RendererThread* master_thread_;
RendererProcessThread* master_thread_;
rational cache_frame_;
RendererDownloadThreadPtr download_thread_;
RenderTexturePtr master_texture_;
private slots:
void ThreadCallback();
@@ -0,0 +1,105 @@
#include "rendererdownloadthread.h"
#include <QFile>
#include "render/pixelservice.h"
RendererDownloadThread::RendererDownloadThread(QOpenGLContext *share_ctx,
const int &width,
const int &height,
const olive::PixelFormat &format,
const olive::RenderMode &mode) :
RendererThreadBase(share_ctx, width, height, format, mode)
{
}
void RendererDownloadThread::Queue(RenderTexturePtr texture, const QString& fn)
{
texture_queue_lock_.lock();
texture_queue_.append(texture);
download_filenames_.append(fn);
wait_cond_.wakeAll();
texture_queue_lock_.unlock();
}
void RendererDownloadThread::ProcessLoop()
{
QOpenGLFunctions* f = render_instance()->context()->functions();
QOpenGLExtraFunctions* xf = render_instance()->context()->extraFunctions();
f->glGenFramebuffers(1, &read_buffer_);
RenderTexturePtr working_texture;
QString working_filename;
int buffer_size = PixelService::GetBufferSize(render_instance()->format(),
render_instance()->width(),
render_instance()->height());
uchar* data_buffer = new uchar[buffer_size];
while (!Cancelled()) {
// Check queue for textures to download (use mutex to prevent collisions)
texture_queue_lock_.lock();
do {
if (texture_queue_.isEmpty()) {
working_texture = nullptr;
} else {
working_texture = texture_queue_.takeFirst();
working_filename = download_filenames_.takeFirst();
}
if (working_texture == nullptr) {
// Main waiting condition
wait_cond_.wait(&texture_queue_lock_);
}
} while (working_texture == nullptr);
texture_queue_lock_.unlock();
// Download the texture
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, read_buffer_);
xf->glFramebufferTexture2D(GL_READ_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
working_texture->texture(),
0);
PixelFormatInfo format_info = PixelService::GetPixelFormatInfo(working_texture->format());
f->glReadPixels(0,
0,
working_texture->width(),
working_texture->height(),
format_info.pixel_format,
format_info.pixel_type,
data_buffer);
render_instance()->context()->extraFunctions()->glFramebufferTexture2D(
GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0
);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
QFile data_dump(working_filename);
if (data_dump.open(QFile::WriteOnly)) {
data_dump.write(reinterpret_cast<char*>(data_buffer), buffer_size);
data_dump.close();
}
qDebug() << "Saved" << working_filename;
}
delete [] data_buffer;
f->glDeleteFramebuffers(1, &read_buffer_);
}
@@ -0,0 +1,34 @@
#ifndef RENDERERDOWNLOADTHREAD_H
#define RENDERERDOWNLOADTHREAD_H
#include "rendererthreadbase.h"
class RendererDownloadThread : public RendererThreadBase
{
Q_OBJECT
public:
RendererDownloadThread(QOpenGLContext* share_ctx,
const int& width,
const int& height,
const olive::PixelFormat& format,
const olive::RenderMode& mode);
void Queue(RenderTexturePtr texture, const QString &fn);
protected:
virtual void ProcessLoop() override;
private:
GLuint read_buffer_;
QVector<RenderTexturePtr> texture_queue_;
QVector<QString> download_filenames_;
QMutex texture_queue_lock_;
};
using RendererDownloadThreadPtr = std::shared_ptr<RendererDownloadThread>;
#endif // RENDERERDOWNLOADTHREAD_H
@@ -0,0 +1,88 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#include "rendererprocessthread.h"
RendererProcessThread::RendererProcessThread(QOpenGLContext *share_ctx,
const int &width,
const int &height,
const olive::PixelFormat &format,
const olive::RenderMode &mode) :
RendererThreadBase(share_ctx, width, height, format, mode)
{
}
bool RendererProcessThread::Queue(const NodeDependency& dep, bool wait)
{
if (wait) {
// Wait for thread to be available
mutex_.lock();
} else if (!mutex_.tryLock()) {
return false;
}
// We can now change params without the other thread using them
path_ = dep;
// Prepare to wait for thread to respond
caller_mutex_.lock();
// Wake up our main thread
wait_cond_.wakeAll();
mutex_.unlock();
// Wait for thread to start before returning
wait_cond_.wait(&caller_mutex_);
caller_mutex_.unlock();
return true;
}
void RendererProcessThread::ProcessLoop()
{
while (!Cancelled()) {
// Main waiting condition
wait_cond_.wait(&mutex_);
// Wake up main thread
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();
QList<NodeDependency> deps = node_to_process->RunDependencies(output_to_process, path_.time());
// 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
output_to_process->get_value(path_.time());
emit FinishedPath();
}
}
@@ -0,0 +1,55 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#ifndef RENDERERPROCESSTHREAD_H
#define RENDERERPROCESSTHREAD_H
#include "rendererthreadbase.h"
class RendererProcessThread : public RendererThreadBase
{
Q_OBJECT
public:
RendererProcessThread(QOpenGLContext* share_ctx,
const int& width,
const int& height,
const olive::PixelFormat& format,
const olive::RenderMode& mode);
bool Queue(const NodeDependency &dep, bool wait);
protected:
virtual void ProcessLoop() override;
signals:
void RequestSibling(NodeDependency dep);
void FinishedPath();
private:
NodeDependency path_;
rational time_;
};
using RendererProcessThreadPtr = std::shared_ptr<RendererProcessThread>;
#endif // RENDERERPROCESSTHREAD_H
@@ -18,11 +18,11 @@
***/
#include "rendererthread.h"
#include "rendererthreadbase.h"
#include <QDebug>
RendererThread::RendererThread(QOpenGLContext *share_ctx, const int &width, const int &height, const olive::PixelFormat &format, const olive::RenderMode &mode) :
RendererThreadBase::RendererThreadBase(QOpenGLContext *share_ctx, const int &width, const int &height, const olive::PixelFormat &format, const olive::RenderMode &mode) :
share_ctx_(share_ctx),
cancelled_(false),
width_(width),
@@ -33,33 +33,7 @@ RendererThread::RendererThread(QOpenGLContext *share_ctx, const int &width, cons
{
}
bool RendererThread::Queue(const NodeDependency& dep, bool wait)
{
if (wait) {
// Wait for thread to be available
mutex_.lock();
} else if (!mutex_.tryLock()) {
return false;
}
// We can now change params without the other thread using them
path_ = dep;
// Prepare to wait for thread to respond
caller_mutex_.lock();
// Wake up our main thread
wait_cond_.wakeAll();
mutex_.unlock();
// Wait for thread to start before returning
wait_cond_.wait(&caller_mutex_);
caller_mutex_.unlock();
return true;
}
void RendererThread::Cancel()
void RendererThreadBase::Cancel()
{
// Escape main loop
cancelled_ = true;
@@ -68,12 +42,12 @@ void RendererThread::Cancel()
wait();
}
RenderInstance *RendererThread::render_instance()
RenderInstance *RendererThreadBase::render_instance()
{
return render_instance_;
}
void RendererThread::run()
void RendererThreadBase::run()
{
// Lock mutex for main loop
mutex_.lock();
@@ -92,33 +66,8 @@ void RendererThread::run()
if (instance.Start()) {
// Main loop (use Cancel() to exit it)
while (!cancelled_) {
// Main waiting condition
wait_cond_.wait(&mutex_);
ProcessLoop();
// Wake up main thread
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();
QList<NodeDependency> deps = node_to_process->RunDependencies(output_to_process, path_.time());
// 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
output_to_process->get_value(path_.time());
emit FinishedPath();
}
}
// Free all resources
@@ -129,7 +78,12 @@ void RendererThread::run()
mutex_.unlock();
}
void RendererThread::StartThread(QThread::Priority priority)
bool RendererThreadBase::Cancelled()
{
return cancelled_;
}
void RendererThreadBase::StartThread(QThread::Priority priority)
{
caller_mutex_.lock();
@@ -29,33 +29,28 @@
#include "node/node.h"
#include "render/renderinstance.h"
class RendererThread : public QThread
class RendererThreadBase : public QThread
{
Q_OBJECT
public:
RendererThread(QOpenGLContext* share_ctx,
const int& width,
const int& height,
const olive::PixelFormat& format,
const olive::RenderMode& mode);
bool Queue(const NodeDependency &dep, bool wait);
RendererThreadBase(QOpenGLContext* share_ctx,
const int& width,
const int& height,
const olive::PixelFormat& format,
const olive::RenderMode& mode);
void Cancel();
RenderInstance* render_instance();
virtual void run() override;
void StartThread(Priority priority = InheritPriority);
signals:
void RequestSibling(NodeDependency dep);
virtual void run() override;
void FinishedPath();
protected:
virtual void ProcessLoop() = 0;
private:
QOpenGLContext* share_ctx_;
bool Cancelled();
QWaitCondition wait_cond_;
@@ -63,9 +58,8 @@ private:
QMutex caller_mutex_;
NodeDependency path_;
rational time_;
private:
QOpenGLContext* share_ctx_;
bool cancelled_;
@@ -81,6 +75,6 @@ private:
};
using RendererThreadPtr = std::shared_ptr<RendererThread>;
using RendererThreadPtr = std::shared_ptr<RendererThreadBase>;
#endif // RENDERTHREAD_H
+8 -3
View File
@@ -2,13 +2,13 @@
const int kRGBAChannels = 4;
ColorService::ColorService()
ColorService::ColorService(const char* source_space, const char* dest_space)
{
// FIXME: Hardcoded values for testing purposes
OCIO::ConstConfigRcPtr config = OCIO::Config::CreateFromFile("/run/media/matt/Home/OpenColorIO/ocio.configs.0.7v4/nuke-default/config.ocio");
processor = config->getProcessor("srgb",
OCIO::ROLE_SCENE_LINEAR);
processor = config->getProcessor(source_space,
dest_space);
}
void ColorService::ConvertFrame(FramePtr f)
@@ -17,3 +17,8 @@ void ColorService::ConvertFrame(FramePtr f)
processor->apply(img);
}
OpenColorIO::v1::ConstProcessorRcPtr ColorService::GetProcessor()
{
return processor;
}
+4 -1
View File
@@ -6,14 +6,17 @@
namespace OCIO = OCIO_NAMESPACE::v1;
#include "decoder/frame.h"
#include "render/gl/shadergenerators.h"
class ColorService
{
public:
ColorService();
ColorService(const char *source_space, const char *dest_space);
void ConvertFrame(FramePtr f);
OCIO::ConstProcessorRcPtr GetProcessor();
private:
OCIO::ConstProcessorRcPtr processor;
};
+3 -3
View File
@@ -41,9 +41,9 @@ public:
static ShaderPtr DefaultPipeline(const QString &function_name = QString(), const QString &shader_code = QString());
static ShaderPtr OCIOPipeline(QOpenGLContext *ctx,
GLuint &lut_texture,
OCIO::ConstProcessorRcPtr processor,
bool alpha_is_associated);
GLuint &lut_texture,
OCIO::ConstProcessorRcPtr processor,
bool alpha_is_associated);
static QString AlphaDisassociateFunction(const QString& function_name);
static QString AlphaReassociateFunction(const QString& function_name);
-6
View File
@@ -127,16 +127,10 @@ void RenderFramebuffer::AttachInternal(GLuint tex)
// bind framebuffer for attaching
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer_);
// bind texture
f->glBindTexture(GL_TEXTURE_2D, tex);
context_->extraFunctions()->glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0
);
// release texture
f->glBindTexture(GL_TEXTURE_2D, 0);
// release framebuffer
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
+2
View File
@@ -66,6 +66,8 @@ bool RenderInstance::Start()
buffer_.Create(&ctx_);
ctx_.functions()->glViewport(0, 0, width_, height_);
return true;
}
+25 -4
View File
@@ -20,6 +20,7 @@
#include "rendertexture.h"
#include <QDateTime>
#include <QDebug>
#include "render/pixelservice.h"
@@ -139,7 +140,7 @@ void RenderTexture::SwapFrontAndBack()
back_texture_ = temp;
}
void RenderTexture::Upload(void *data)
void RenderTexture::Upload(const void *data)
{
if (!IsCreated()) {
qWarning() << tr("RenderTexture::Upload() called while it wasn't created");
@@ -163,16 +164,36 @@ void RenderTexture::Upload(void *data)
Release();
}
void *RenderTexture::Download() const
uchar *RenderTexture::Download() const
{
if (!IsCreated()) {
qWarning() << tr("RenderTexture::Download() called while it wasn't created");
return nullptr;
}
// FIXME: Implement this
QOpenGLFunctions* f = context_->functions();
return nullptr;
GLuint read_fbo;
f->glGenFramebuffers(1, &read_fbo);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo);
context_->extraFunctions()->glFramebufferTexture2D(
GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0
);
PixelFormatInfo format_info = PixelService::GetPixelFormatInfo(format_);
uchar* data = new uchar[PixelService::GetBufferSize(format_, width_, height_)];
f->glReadPixels(0, 0, width_, height_, format_info.pixel_format, format_info.pixel_type, data);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
f->glDeleteFramebuffers(1, &read_fbo);
return data;
}
void RenderTexture::CreateInternal(void *data)
+2 -2
View File
@@ -64,9 +64,9 @@ public:
const GLuint& back_texture() const;
void SwapFrontAndBack();
void Upload(void* data);
void Upload(const void *data);
void* Download() const;
uchar *Download() const;
private:
void CreateInternal(void *data = nullptr);