began draft of internal node rendering structure

This commit is contained in:
itsmattkc
2019-07-10 23:06:09 -04:00
parent f38e6b876d
commit d76691a9ef
38 changed files with 1617 additions and 14 deletions
+2
View File
@@ -122,6 +122,8 @@ bool FFmpegDecoder::Open()
FramePtr FFmpegDecoder::Retrieve(const rational &timecode, const rational &length)
{
// FIXME: Fill this out
Q_UNUSED(timecode)
Q_UNUSED(length)
+12 -7
View File
@@ -37,25 +37,30 @@ extern "C" {
class Frame
{
public:
// Normal constructor
enum Type {
kNative,
kAVFrame
};
/// Normal constructor
Frame();
// AVFrame constructor
/// AVFrame constructor
Frame(AVFrame* f);
// Copy constructor
/// Copy constructor
Frame(const Frame& f);
// Move constructor
/// Move constructor
Frame(Frame&& f);
// Copy assignment operator
/// Copy assignment operator
Frame& operator=(const Frame& f);
// Move assignment operator
/// Move assignment operator
Frame& operator=(Frame&& f);
// Destructor
/// Destructor
~Frame();
/**
+7 -2
View File
@@ -14,16 +14,21 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(generator)
add_subdirectory(output)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/edge.h
node/edge.cpp
node/node.h
node/node.cpp
node/graph.h
node/graph.cpp
node/input.h
node/input.cpp
node/keyframe.h
node/keyframe.cpp
node/node.h
node/node.cpp
node/output.h
node/output.cpp
node/param.h
+22
View File
@@ -0,0 +1,22 @@
# 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/>.
add_subdirectory(solid)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
PARENT_SCOPE
)
+22
View File
@@ -0,0 +1,22 @@
# 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/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/generator/solid/solid.h
node/generator/solid/solid.cpp
PARENT_SCOPE
)
+14
View File
@@ -0,0 +1,14 @@
#include "solid.h"
SolidGenerator::SolidGenerator(QObject *parent) :
Node(parent)
{
}
void SolidGenerator::Process(const rational &time)
{
Q_UNUSED(time)
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef SOLIDGENERATOR_H
#define SOLIDGENERATOR_H
#include "node/node.h"
class SolidGenerator : public Node
{
public:
SolidGenerator(QObject* parent = nullptr);
virtual void Process(const rational &time) override;
private:
NodeOutput* texture_output_;
};
#endif // SOLIDGENERATOR_H
+42
View File
@@ -20,10 +20,14 @@
#include "input.h"
#include "output.h"
NodeInput::NodeInput(Node* parent) :
NodeParam(parent),
can_accept_multiple_inputs_(false)
{
// Have at least one keyframe/value active at any time
keyframes_.append(NodeKeyframe());
}
NodeParam::Type NodeInput::type()
@@ -50,3 +54,41 @@ void NodeInput::set_can_accept_multiple_inputs(bool b)
{
can_accept_multiple_inputs_ = b;
}
QVariant NodeInput::get_value(const rational &time)
{
/// Determine if this input has any connections to it
switch (edges_.size()) {
/// No connections - use the internal value
case 0:
// FIXME: Re-implement keyframing
return keyframes_.first().value();
/// One connection - use the output of the connected Node
case 1:
return edges_.first()->output()->get_value(time);
/// Multiple connections - rare, return a list of the outputs of the connected Nodes
default:
{
QList<QVariant> values;
for (int i=0;i<edges_.size();i++) {
values.append(edges_.at(i)->output()->get_value(time));
}
return values;
}
}
}
bool NodeInput::keyframing()
{
return keyframing_;
}
void NodeInput::set_keyframing(bool k)
{
keyframing_ = k;
}
+10
View File
@@ -21,6 +21,7 @@
#ifndef NODEINPUT_H
#define NODEINPUT_H
#include "keyframe.h"
#include "param.h"
class NodeInput : public NodeParam
@@ -37,9 +38,18 @@ public:
bool can_accept_multiple_inputs();
void set_can_accept_multiple_inputs(bool b);
QVariant get_value(const rational &time);
bool keyframing();
void set_keyframing(bool k);
private:
QList<DataType> inputs_;
QList<NodeKeyframe> keyframes_;
bool keyframing_;
bool can_accept_multiple_inputs_;
};
+59
View File
@@ -0,0 +1,59 @@
/***
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 "keyframe.h"
NodeKeyframe::NodeKeyframe() :
time_(0),
value_(0),
type_(kLinear)
{
}
const rational &NodeKeyframe::time()
{
return time_;
}
void NodeKeyframe::set_time(const rational &time)
{
time_ = time;
}
const QVariant &NodeKeyframe::value()
{
return value_;
}
void NodeKeyframe::set_value(const QVariant &value)
{
value_ = value;
}
const NodeKeyframe::Type &NodeKeyframe::type()
{
return type_;
}
void NodeKeyframe::set_type(const NodeKeyframe::Type &type)
{
type_ = type;
}
+57
View File
@@ -0,0 +1,57 @@
/***
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 NODEKEYFRAME_H
#define NODEKEYFRAME_H
#include <QVariant>
#include "rational.h"
class NodeKeyframe
{
public:
enum Type {
kLinear,
kHold,
kBezier
};
NodeKeyframe();
const rational& time();
void set_time(const rational& time);
const QVariant& value();
void set_value(const QVariant &value);
const Type& type();
void set_type(const Type& type);
private:
rational time_;
QVariant value_;
Type type_;
};
#endif // NODEKEYFRAME_H
+3
View File
@@ -24,11 +24,14 @@
#include <QObject>
#include "node/param.h"
#include "rational.h"
class Node : public QObject
{
public:
Node(QObject* parent = nullptr);
virtual void Process(const rational& time) = 0;
};
#endif // NODE_H
+16
View File
@@ -20,6 +20,8 @@
#include "output.h"
#include "node/node.h"
NodeOutput::NodeOutput(Node *parent) :
NodeParam(parent)
{
@@ -40,3 +42,17 @@ void NodeOutput::set_data_type(const NodeParam::DataType &type)
{
data_type_ = type;
}
const QVariant &NodeOutput::get_value(const rational& time)
{
// Node::Process() should put the correct value in this output
parent()->Process(time);
// The value should be have been set by this point
return value_;
}
void NodeOutput::set_value(const QVariant &value)
{
value_ = value;
}
+5
View File
@@ -33,8 +33,13 @@ public:
const DataType& data_type();
void set_data_type(const DataType& type);
virtual const QVariant& get_value(const rational &time);
virtual void set_value(const QVariant& value);
private:
DataType data_type_;
QVariant value_;
};
#endif // NODEOUTPUT_H
+22
View File
@@ -0,0 +1,22 @@
# 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/>.
add_subdirectory(viewer)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
PARENT_SCOPE
)
+22
View File
@@ -0,0 +1,22 @@
# 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/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/output/viewer/viewer.h
node/output/viewer/viewer.cpp
PARENT_SCOPE
)
+6
View File
@@ -0,0 +1,6 @@
#include "viewer.h"
ViewerOutput::ViewerOutput(QObject* parent) :
Node(parent)
{
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef VIEWER_H
#define VIEWER_H
#include "node/node.h"
class ViewerOutput : public Node
{
public:
ViewerOutput(QObject* parent = nullptr);
private:
NodeInput* texture_input_;
};
#endif // VIEWER_H
+5
View File
@@ -40,6 +40,11 @@ void NodeParam::set_name(const QString &name)
name_ = name;
}
Node *NodeParam::parent()
{
return static_cast<Node*>(QObject::parent());
}
bool NodeParam::AreDataTypesCompatible(const NodeParam::DataType &output_type, const NodeParam::DataType &input_type)
{
if (input_type == output_type) {
+8 -1
View File
@@ -22,8 +22,10 @@
#define NODEPARAM_H
#include <QObject>
#include <QVariant>
#include "node/edge.h"
#include "rational.h"
class Node;
@@ -58,6 +60,8 @@ public:
const QString& name();
void set_name(const QString& name);
Node* parent();
static bool AreDataTypesCompatible(const DataType& output_type, const DataType& input_type);
static bool AreDataTypesCompatible(const DataType& output_type, const QList<DataType>& input_types);
@@ -66,10 +70,13 @@ public:
static QString GetDefaultDataTypeName(const DataType &type);
private:
protected:
QVector<NodeEdgePtr> edges_;
private:
QString name_;
};
#endif // NODEPARAM_H
+9
View File
@@ -15,8 +15,17 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(gl)
add_subdirectory(renderer)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
#render/imagecache.h
#render/imagecache.cpp
#render/memorybuffer.h
#render/memorybuffer.cpp
render/pixelformat.h
render/pixelformat.cpp
render/texturebuffer.h
render/texturebuffer.cpp
PARENT_SCOPE
)
+2 -2
View File
@@ -16,8 +16,8 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
render/gl/glfunc.h
render/gl/glfunc.cpp
render/gl/functions.h
render/gl/functions.cpp
render/gl/shadergenerators.h
render/gl/shadergenerators.cpp
render/gl/shaderptr.h
@@ -18,7 +18,7 @@
***/
#include "glfunc.h"
#include "functions.h"
#include <QOpenGLFunctions>
#include <QOpenGLVertexArrayObject>
+313
View File
@@ -0,0 +1,313 @@
/***
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 "imagecache.h"
#include <QDebug>
ImageCache::ImageCache() :
ctx_(nullptr),
width_(0),
height_(0)
{
}
ImageCache::~ImageCache()
{
buffer_array_mutex_.lock();
Clear();
buffer_array_mutex_.unlock();
}
void ImageCache::SetParameters(QOpenGLContext *ctx, int width, int height)
{
buffer_array_mutex_.lock();
ctx_ = ctx;
if (ctx_ != nullptr) {
Q_ASSERT(width > 0 && height > 0);
width_ = width;
height_ = height;
}
Clear();
buffer_array_mutex_.unlock();
}
int ImageCache::RequestBuffer(Ref* r, const BufferType& type, const olive::PixelFormat& format, int width, int height)
{
if (type == kTexBuf && (ctx_ == nullptr || width_ == 0 || height_ == 0)) {
qWarning() << tr("Texture cache request made without valid parameters (%1: %2, %3").arg(QString::number(reinterpret_cast<quintptr>(ctx_)),
QString::number(width_),
QString::number(height_));
return -1;
}
buffer_array_mutex_.lock();
int buffer = RequestBufferInternal(r, type, format, width, height);
buffer_array_mutex_.unlock();
return buffer;
}
int ImageCache::RequestBufferInternal(Ref *r, const BufferType& type, const olive::PixelFormat& format, int width, int height)
{
Q_ASSERT(type != kInvalidBuf);
QList<int>& relinquished = (type == kMemBuf) ? img_relinquished_ : tex_relinquished_;
QList<Ref*>& refs = (type == kMemBuf) ? img_refs_ : tex_refs_;
QList<time_t>& access_times = (type == kMemBuf) ? img_access_times_ : tex_access_times_;
// Try to return a relinquished buffer
if (!relinquished.isEmpty()) {
if (type == kTexBuf) {
int buf_index = relinquished.takeFirst();
refs.replace(buf_index, r);
return buf_index;
} else if (type == kMemBuf) {
// Check for a relinquished buffer with the desired size
//
// TODO consider a database for sorting through these buffers
//
for (int i=0;i<relinquished.size();i++) {
const MemoryBuffer& b = img_buffers_.at(relinquished.at(i));
if (b.width() == width && b.height() == height) {
// This buffer fits, we'll use it
int buffer_index = relinquished.takeAt(i);
refs.replace(buffer_index, r);
return buffer_index;
}
}
}
}
// If no buffer was available, we may have to create a new one
// Check if we have enough memory (according to user-defined limits in the Config), if we don't, try to relinquish an
// old buffer and return that.
if (OutOfMemory()) {
//
// TODO no support for a MemBuf's variable size
//
int least_recent_access = 0;
// Loop through buffers for the oldest accessed buffer
for (int i=1;i<access_times.size();i++) {
if (access_times.at(i) < access_times.at(least_recent_access)
&& refs.at(i) != nullptr) { // ensure this buffer has not been relinquished
least_recent_access = i;
}
}
// Relinquish this buffer
refs.at(least_recent_access)->Relinquish();
refs.replace(least_recent_access, r);
return least_recent_access;
}
// Otherwise, just generate a new buffer
int index = -1;
switch (type) {
case kMemBuf:
index = img_buffers_.size();
img_buffers_.append(MemoryBuffer());
img_buffers_.last().Create(width_, height_, format);
break;
case kTexBuf:
index = tex_buffers_.size();
tex_buffers_.append(TextureBuffer());
tex_buffers_.last().Create(ctx_, format, width_, height_);
break;
default:
Q_ASSERT(false);
}
refs.append(r);
access_times.append(time(nullptr));
return index;
}
void ImageCache::RelinquishBuffer(int index, const BufferType &type)
{
buffer_array_mutex_.lock();
switch (type) {
case kMemBuf:
img_refs_.replace(index, nullptr);
img_relinquished_.append(index);
break;
case kTexBuf:
tex_refs_.replace(index, nullptr);
tex_relinquished_.append(index);
break;
default:
qFatal("Invalid buffer type on ImageCache::RelinquishBuffer");
}
buffer_array_mutex_.unlock();
}
void *ImageCache::Buffer(int index, const BufferType &type)
{
switch (type) {
case kMemBuf:
img_access_times_.replace(index, time(nullptr));
return &img_buffers_[index];
case kTexBuf:
tex_access_times_.replace(index, time(nullptr));
return &tex_buffers_[index];
default:
qFatal("Invalid buffer type on ImageCache::Buffer");
}
}
bool ImageCache::OutOfMemory()
{
// TODO actually check if we have any memory or not
return false;
}
void ImageCache::Clear()
{
for (int i=0;i<img_refs_.size();i++) {
img_refs_.at(i)->Relinquish();
}
for (int i=0;i<tex_refs_.size();i++) {
tex_refs_.at(i)->Relinquish();
}
img_refs_.clear();
tex_refs_.clear();
img_buffers_.clear();
tex_buffers_.clear();
img_relinquished_.clear();
tex_relinquished_.clear();
}
ImageCache::Ref::Ref(ImageCache *cache) :
buffer_type_(kInvalidBuf),
width_(cache->width_),
height_(cache->height_),
cache_(cache),
buffer_(-1)
{
}
ImageCache::Ref::~Ref()
{
Relinquish();
}
void *ImageCache::Ref::BufferInternal()
{
// If we don't have a buffer yet, request one
if (buffer_ == -1) {
Request();
}
// If we didn't receive one, return null
if (buffer_ == -1) {
return nullptr;
}
// Otherwise, return the buffer we received
return cache_->Buffer(buffer_, buffer_type_);
}
void ImageCache::Ref::Relinquish()
{
if (buffer_ == -1) {
return;
}
cache_->RelinquishBuffer(buffer_, buffer_type_);
buffer_ = -1;
}
void ImageCache::Ref::Request()
{
// Check if we already have a buffer, in which case we don't need to request a new one
if (buffer_ != -1) {
return;
}
// Check if we have a valid buffer type to request
if (buffer_type_ == kInvalidBuf) {
qWarning() << tr("Tried to request an invalid buffer type");
return;
}
buffer_ = cache_->RequestBuffer(this, buffer_type_, width_, height_);
}
ImageCache::ImgRef::ImgRef(ImageCache *cache) :
Ref(cache)
{
buffer_type_ = kMemBuf;
}
void ImageCache::ImgRef::SetSize(int w, int h)
{
width_ = w;
height_ = h;
Relinquish();
}
MemoryBuffer *ImageCache::ImgRef::buffer()
{
return static_cast<MemoryBuffer*>(BufferInternal());
}
ImageCache::TexRef::TexRef(ImageCache *cache) :
Ref(cache)
{
buffer_type_ = kTexBuf;
}
TextureBuffer *ImageCache::TexRef::buffer()
{
return static_cast<TextureBuffer*>(BufferInternal());
}
+111
View File
@@ -0,0 +1,111 @@
/***
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 MEMORYCACHE_H
#define MEMORYCACHE_H
#include <QList>
#include <QMutex>
#include "texturebuffer.h"
#include "memorybuffer.h"
class ImageCache : public QObject
{
public:
enum BufferType {
kInvalidBuf, // No buffer
kMemBuf, // RAM (CPU) buffer
kTexBuf // VRAM (GPU) buffer
};
class Ref {
public:
Ref(ImageCache* cache);
~Ref();
void Relinquish();
protected:
void* BufferInternal();
BufferType buffer_type_;
int width_;
int height_;
private:
void Request();
ImageCache* cache_;
int buffer_;
};
class ImgRef : public Ref {
public:
ImgRef(ImageCache* cache);
void SetSize(int w, int h);
MemoryBuffer* buffer();
};
class TexRef : public Ref {
public:
TexRef(ImageCache* cache);
TextureBuffer* buffer();
};
ImageCache();
~ImageCache();
void SetParameters(QOpenGLContext* ctx, int width, int height);
private:
int RequestBuffer(Ref *r, const BufferType& type, const olive::PixelFormat &format, int width, int height);
int RequestBufferInternal(Ref *r, const BufferType& type, const olive::PixelFormat &format, int width, int height);
void RelinquishBuffer(int index, const BufferType& type);
void *Buffer(int index, const BufferType &type);
bool OutOfMemory();
void Clear();
QList<MemoryBuffer> img_buffers_;
QList<Ref*> img_refs_;
QList<time_t> img_access_times_;
QList<int> img_relinquished_;
QList<TextureBuffer> tex_buffers_;
QList<Ref*> tex_refs_;
QList<time_t> tex_access_times_;
QList<int> tex_relinquished_;
QOpenGLContext* ctx_;
int width_;
int height_;
QMutex buffer_array_mutex_;
};
#endif // MEMORYCACHE_H
+59
View File
@@ -0,0 +1,59 @@
/***
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 "memorybuffer.h"
MemoryBuffer::MemoryBuffer()
{
}
void MemoryBuffer::Create(int width, int height, const olive::PixelFormat &format)
{
width_ = width;
height_ = height;
format_ = format;
data_.resize(PixelService::GetBufferSize(format, width, height));
}
const int &MemoryBuffer::width() const
{
return width_;
}
const int &MemoryBuffer::height() const
{
return height_;
}
const olive::PixelFormat &MemoryBuffer::format() const
{
return format_;
}
uint8_t *MemoryBuffer::data()
{
return data_.data();
}
const uint8_t *MemoryBuffer::const_data() const
{
return data_.constData();
}
+48
View File
@@ -0,0 +1,48 @@
/***
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 MEMORYBUFFER_H
#define MEMORYBUFFER_H
#include <QVector>
#include "pixelformat.h"
class MemoryBuffer
{
public:
MemoryBuffer();
void Create(int width, int height, const olive::PixelFormat &format);
const int& width() const;
const int& height() const;
const olive::PixelFormat& format() const;
uint8_t* data();
const uint8_t* const_data() const;
private:
QVector<uint8_t> data_;
int width_;
int height_;
olive::PixelFormat format_;
};
#endif // MEMORYBUFFER_H
+84
View File
@@ -0,0 +1,84 @@
/***
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 "pixelformat.h"
#include <QCoreApplication>
const int kRGBAChannels = 4;
PixelService::PixelService()
{
}
PixelFormatInfo PixelService::GetPixelFormatInfo(const olive::PixelFormat &format)
{
PixelFormatInfo info;
switch (format) {
case olive::PIX_FMT_RGBA8:
info.name = tr("8-bit");
info.internal_format = GL_RGBA8;
info.pixel_type = GL_UNSIGNED_BYTE;
break;
case olive::PIX_FMT_RGBA16:
info.name = tr("16-bit Integer");
info.internal_format = GL_RGBA16;
info.pixel_type = GL_UNSIGNED_SHORT;
break;
case olive::PIX_FMT_RGBA16F:
info.name = tr("Half-Float (16-bit)");
info.internal_format = GL_RGBA16F;
info.pixel_type = GL_HALF_FLOAT;
break;
case olive::PIX_FMT_RGBA32F:
info.name = tr("Full-Float (32-bit)");
info.internal_format = GL_RGBA32F;
info.pixel_type = GL_FLOAT;
break;
default:
qFatal("Invalid pixel format requested");
}
info.pixel_format = GL_RGBA;
info.bytes_per_pixel = BytesPerPixel(format);
return info;
}
int PixelService::GetBufferSize(const olive::PixelFormat &format, const int &width, const int &height)
{
return BytesPerPixel(format) * width * height;
}
int PixelService::BytesPerPixel(const olive::PixelFormat &format)
{
switch (format) {
case olive::PIX_FMT_RGBA8:
return 1 * kRGBAChannels;
case olive::PIX_FMT_RGBA16:
case olive::PIX_FMT_RGBA16F:
return 2 * kRGBAChannels;
case olive::PIX_FMT_RGBA32F:
return 4 * kRGBAChannels;
default:
qFatal("Invalid pixel format requested");
}
}
+102
View File
@@ -0,0 +1,102 @@
/***
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 BITDEPTHS_H
#define BITDEPTHS_H
#include <QString>
#include <QVector>
#include <QOpenGLExtraFunctions>
/**
* @brief A struct of information pertaining to each enum PixelFormat.
*
* Primarily this is a means of retrieving OpenGL texture information for different pixel formats/bit depths. Both
* RAM and VRAM buffers will need a PixelFormat. To keep consistency between the OpenGL code and CPU code when using
* a given PixelFormat, the PixelFormatInfo struct contains all necessary variables that you'll need to plug into
* OpenGL.
*
* Use the static function PixelService::GetPixelFormatInfo to generate a PixelFormatInfo object.
*/
struct PixelFormatInfo {
QString name;
GLint internal_format;
GLenum pixel_format;
GLenum pixel_type;
int bytes_per_pixel;
};
namespace olive {
/**
* @brief Olive's internal supported pixel formats.
*/
enum PixelFormat {
PIX_FMT_RGBA8,
PIX_FMT_RGBA16,
PIX_FMT_RGBA16F,
PIX_FMT_RGBA32F,
PIX_FMT_COUNT
};
}
class PixelService : public QObject {
public:
PixelService();
/**
* @brief Return a PixelFormatInfo containing information for a certain format
*
* \see PixelFormatInfo
*/
static PixelFormatInfo GetPixelFormatInfo(const olive::PixelFormat& format);
/**
* @brief Returns the minimum buffer size (in bytes) necessary for a given format, width, and height.
*
* @param format
*
* The format of the data the buffer should contain. Must be a member of the olive::PixelFormat enum.
*
* @param width
*
* The width (in pixels) of the buffer.
*
* @param height
*
* The height (in pixels) of the buffer.
*/
static int GetBufferSize(const olive::PixelFormat &format, const int& width, const int& height);
/**
* @brief Returns the number of bytes per pixel for a certain format
*
* Different formats use different sizes of data for pixels. Use this function to determine how many bytes a pixel
* requires for a certain format. The number of bytes will always be a multiple of 4 since all formats use RGBA and
* are at least 1 bpc.
*/
static int BytesPerPixel(const olive::PixelFormat& format);
private:
};
#endif // BITDEPTHS_H
+24
View File
@@ -0,0 +1,24 @@
# 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/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
render/renderer/renderer.h
render/renderer/renderer.cpp
render/renderer/rendererthread.h
render/renderer/rendererthread.cpp
PARENT_SCOPE
)
+70
View File
@@ -0,0 +1,70 @@
/***
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 "renderer.h"
Renderer::Renderer() :
started_(false)
{
}
void Renderer::Start()
{
if (started_) {
return;
}
threads_.resize(QThread::idealThreadCount());
for (int i=0;i<threads_.size();i++) {
threads_[i] = new RendererThread();
threads_[i]->run();
}
started_ = true;
}
void Renderer::Stop()
{
if (!started_) {
return;
}
started_ = false;
for (int i=0;i<threads_.size();i++) {
threads_[i]->Cancel();
delete threads_[i];
}
threads_.clear();
}
/*RendererThread *Renderer::CurrentThread()
{
for (int i=0;i<threads_.size();i++) {
if (threads_.at(i) == QThread::currentThread()) {
return threads_.at(i);
}
}
return nullptr;
}*/
+43
View File
@@ -0,0 +1,43 @@
/***
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 RENDERER_H
#define RENDERER_H
#include "render/renderer/rendererthread.h"
class Renderer
{
public:
Renderer();
void Start();
void Stop();
//RendererThread* CurrentThread();
private:
QVector<RendererThread*> threads_;
bool started_;
};
#endif // RENDERER_H
+106
View File
@@ -0,0 +1,106 @@
/***
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 "rendererthread.h"
#include <QDebug>
RendererThread::RendererThread() :
cancelled_(false)
{
}
bool RendererThread::Queue(Node *n, const rational& time)
{
// If the thread is inactive, tryLock() will succeed
if (mutex_.tryLock()) {
// The mutex is locked in the calling thread now, so we can change the active Node
node_ = n;
time_ = time;
// We can now wake up our main thread
wait_cond_.wakeAll();
mutex_.unlock();
// Wait for thread to start before returning
caller_mutex_.lock();
caller_mutex_.unlock();
return true;
}
return false;
}
void RendererThread::Cancel()
{
// Escape main loop
cancelled_ = true;
// Wait until thread is finished before returning
wait();
}
void RendererThread::run()
{
// Create OpenGL context (automatically destroys any existing if there is one)
if (!ctx_.create()) {
qWarning() << tr("Failed to create OpenGL context in thread %1").arg(reinterpret_cast<quintptr>(this));
return;
}
// Create offscreen surface
surface_.create();
// Make context current on that surface
if (!ctx_.makeCurrent(&surface_)) {
qWarning() << tr("Failed to makeCurrent() on offscreen surface in thread %1").arg(reinterpret_cast<quintptr>(this));
surface_.destroy();
return;
}
// Lock mutex for main loop
mutex_.lock();
// Main loop (use Cancel() to exit it)
while (!cancelled_) {
// Lock the caller mutex (used in Queue() for thread synchronization)
caller_mutex_.lock();
// Main waiting condition
wait_cond_.wait(&mutex_);
// Unlock the caller mutex
caller_mutex_.unlock();
// Process the Node
node_->Process(time_);
}
// Release OpenGL context
ctx_.doneCurrent();
// Destroy offscreen surface
surface_.destroy();
// Unlock mutex before exiting
mutex_.unlock();
}
+68
View File
@@ -0,0 +1,68 @@
/***
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 RENDERTHREAD_H
#define RENDERTHREAD_H
#include <QMutex>
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QThread>
#include <QWaitCondition>
#include "node/node.h"
#include "render/texturebuffer.h"
class RendererThread : public QThread
{
public:
RendererThread();
QOpenGLContext* context();
TextureBuffer* buffer();
bool Queue(Node* n, const rational &time);
void Cancel();
virtual void run() override;
private:
QOpenGLContext ctx_;
QOffscreenSurface surface_;
TextureBuffer buffer_;
QWaitCondition wait_cond_;
QMutex mutex_;
QMutex caller_mutex_;
Node* node_;
rational time_;
bool cancelled_;
};
#endif // RENDERTHREAD_H
+150
View File
@@ -0,0 +1,150 @@
/***
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 "texturebuffer.h"
#include <QOpenGLFunctions>
#include <QOpenGLExtraFunctions>
TextureBuffer::TextureBuffer() :
ctx_(nullptr),
buffer_(0),
texture_(0)
{}
TextureBuffer::~TextureBuffer()
{
Destroy();
}
bool TextureBuffer::IsCreated()
{
return (ctx_ != nullptr);
}
void TextureBuffer::Create(QOpenGLContext *ctx, const olive::PixelFormat &format, int width, int height)
{
// free any previous textures
Destroy();
// set context to new context provided
ctx_ = ctx;
QOpenGLFunctions* f = ctx->functions();
// create framebuffer object
f->glGenFramebuffers(1, &buffer_);
// create texture
f->glGenTextures(1, &texture_);
// bind framebuffer for attaching
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer_);
// bind texture
f->glBindTexture(GL_TEXTURE_2D, texture_);
// allocate storage for texture
const PixelFormatInfo& bit_depth = PixelService::GetPixelFormatInfo(format);
ctx->functions()->glTexImage2D(
GL_TEXTURE_2D,
0,
bit_depth.internal_format,
width,
height,
0,
bit_depth.pixel_format,
bit_depth.pixel_type,
nullptr
);
// set texture filtering to bilinear
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// attach texture to framebuffer
ctx->extraFunctions()->glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0
);
// clear new texture
ctx->functions()->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
ctx->functions()->glClear(GL_COLOR_BUFFER_BIT);
// release texture
f->glBindTexture(GL_TEXTURE_2D, 0);
// release framebuffer
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
void TextureBuffer::Destroy()
{
if (ctx_ != nullptr) {
ctx_->functions()->glDeleteFramebuffers(1, &buffer_);
ctx_->functions()->glDeleteTextures(1, &texture_);
ctx_ = nullptr;
}
}
void TextureBuffer::BindBuffer() const
{
if (ctx_ == nullptr) {
return;
}
ctx_->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer_);
}
void TextureBuffer::ReleaseBuffer() const
{
if (ctx_ == nullptr) {
return;
}
ctx_->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
void TextureBuffer::BindTexture() const
{
if (ctx_ == nullptr) {
return;
}
ctx_->functions()->glBindTexture(GL_TEXTURE_2D, texture_);
}
void TextureBuffer::ReleaseTexture() const
{
if (ctx_ == nullptr) {
return;
}
ctx_->functions()->glBindTexture(GL_TEXTURE_2D, 0);
}
const GLuint &TextureBuffer::buffer() const
{
return buffer_;
}
const GLuint &TextureBuffer::texture() const
{
return texture_;
}
+60
View File
@@ -0,0 +1,60 @@
/***
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 FRAMEBUFFEROBJECT_H
#define FRAMEBUFFEROBJECT_H
#include <QOpenGLContext>
#include "pixelformat.h"
/**
* @brief A class for managing an OpenGL framebuffer and attached texture
*
* The GPU pipeline will frequently need framebuffers for drawing onto textures. The TextureBuffer is a convenience
* class to handle the creation, management, and destruction of a framebuffer with a texture attachment.
*
* After creating a new TextureBuffer, call Create() when a valid OpenGL context is available.
*/
class TextureBuffer
{
public:
TextureBuffer();
~TextureBuffer();
bool IsCreated();
void Create(QOpenGLContext* ctx, const olive::PixelFormat& format, int width, int height);
void Destroy();
const GLuint& buffer() const;
const GLuint& texture() const;
void BindBuffer() const;
void ReleaseBuffer() const;
void BindTexture() const;
void ReleaseTexture() const;
private:
QOpenGLContext* ctx_;
GLuint buffer_;
GLuint texture_;
};
#endif // FRAMEBUFFEROBJECT_H
+1 -1
View File
@@ -24,7 +24,7 @@
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include "render/gl/glfunc.h"
#include "render/gl/functions.h"
#include "render/gl/shadergenerators.h"
ViewerGLWidget::ViewerGLWidget(QWidget *parent) :