merged all drawing functions into a single shader processing function
This commit is contained in:
@@ -187,4 +187,16 @@ QString FileFunctions::EnsureFilenameExtension(QString fn, const QString &extens
|
||||
return fn;
|
||||
}
|
||||
|
||||
QString FileFunctions::ReadFileAsString(const QString &filename)
|
||||
{
|
||||
QFile f(filename);
|
||||
QString file_data;
|
||||
if (f.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QTextStream text_stream(&f);
|
||||
file_data = text_stream.readAll();
|
||||
f.close();
|
||||
}
|
||||
return file_data;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -65,6 +65,8 @@ public:
|
||||
*/
|
||||
static QString EnsureFilenameExtension(QString fn, const QString& extension);
|
||||
|
||||
static QString ReadFileAsString(const QString& filename);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ NodeValueTable PanNode::Value(NodeValueDatabase &value) const
|
||||
NodeValueTable table = value.Merge();
|
||||
|
||||
if (job.HasSamples()) {
|
||||
float pan_volume = job.GetValue(panning_input_).data().toFloat();
|
||||
float pan_volume = job.GetValue(panning_input_).data.toFloat();
|
||||
if (panning_input_->is_static()) {
|
||||
if (!qIsNull(pan_volume) && job.samples()->audio_params().channel_count() == 2) {
|
||||
if (pan_volume > 0) {
|
||||
|
||||
@@ -56,7 +56,7 @@ ShaderCode CrossDissolveTransition::GetShaderCode(const QString &shader_id) cons
|
||||
{
|
||||
Q_UNUSED(shader_id)
|
||||
|
||||
return ShaderCode(Node::ReadFileAsString(":/shaders/crossdissolve.frag"), QString());
|
||||
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/crossdissolve.frag"), QString());
|
||||
}
|
||||
|
||||
void CrossDissolveTransition::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const
|
||||
|
||||
@@ -57,7 +57,7 @@ ShaderCode DipToColorTransition::GetShaderCode(const QString &shader_id) const
|
||||
{
|
||||
Q_UNUSED(shader_id)
|
||||
|
||||
return ShaderCode(Node::ReadFileAsString(":/shaders/diptoblack.frag"), QString());
|
||||
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/diptoblack.frag"), QString());
|
||||
}
|
||||
|
||||
void DipToColorTransition::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &job) const
|
||||
|
||||
@@ -161,15 +161,15 @@ void TransitionBlock::InsertTransitionTimes(AcceleratedJob *job, const double &t
|
||||
{
|
||||
// Provides total transition progress from 0.0 (start) - 1.0 (end)
|
||||
job->InsertValue(QStringLiteral("ove_tprog_all"),
|
||||
NodeValue(NodeParam::kFloat, GetTotalProgress(time), this));
|
||||
ShaderValue(GetTotalProgress(time), NodeParam::kFloat));
|
||||
|
||||
// Provides progress of out section from 1.0 (start) - 0.0 (end)
|
||||
job->InsertValue(QStringLiteral("ove_tprog_out"),
|
||||
NodeValue(NodeParam::kFloat, GetOutProgress(time), this));
|
||||
ShaderValue(GetOutProgress(time), NodeParam::kFloat));
|
||||
|
||||
// Provides progress of in section from 0.0 (start) - 1.0 (end)
|
||||
job->InsertValue(QStringLiteral("ove_tprog_in"),
|
||||
NodeValue(NodeParam::kFloat, GetInProgress(time), this));
|
||||
ShaderValue(GetInProgress(time), NodeParam::kFloat));
|
||||
}
|
||||
|
||||
void TransitionBlock::BlockConnected(NodeEdgePtr edge)
|
||||
|
||||
@@ -83,7 +83,7 @@ void BlurFilterNode::Retranslate()
|
||||
ShaderCode BlurFilterNode::GetShaderCode(const QString &shader_id) const
|
||||
{
|
||||
Q_UNUSED(shader_id)
|
||||
return ShaderCode(ReadFileAsString(":/shaders/blur.frag"), QString());
|
||||
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/blur.frag"), QString());
|
||||
}
|
||||
|
||||
NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const
|
||||
@@ -100,19 +100,19 @@ NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const
|
||||
NodeValueTable table = value.Merge();
|
||||
|
||||
// If there's no texture, no need to run an operation
|
||||
if (!job.GetValue(texture_input_).data().isNull()) {
|
||||
if (!job.GetValue(texture_input_).data.isNull()) {
|
||||
|
||||
// Check if radius > 0, and both "horiz" and/or "vert" are enabled
|
||||
if ((job.GetValue(horiz_input_).data().toBool() || job.GetValue(vert_input_).data().toBool())
|
||||
&& job.GetValue(radius_input_).data().toDouble() > 0.0) {
|
||||
if ((job.GetValue(horiz_input_).data.toBool() || job.GetValue(vert_input_).data.toBool())
|
||||
&& job.GetValue(radius_input_).data.toDouble() > 0.0) {
|
||||
|
||||
// Set iteration count to 2 if we're blurring both horizontally and vertically
|
||||
if (job.GetValue(horiz_input_).data().toBool() && job.GetValue(vert_input_).data().toBool()) {
|
||||
if (job.GetValue(horiz_input_).data.toBool() && job.GetValue(vert_input_).data.toBool()) {
|
||||
job.SetIterations(2, texture_input_);
|
||||
}
|
||||
|
||||
// If we're not repeating pixels, expect an alpha channel to appear
|
||||
if (!job.GetValue(repeat_edge_pixels_input_).data().toBool()) {
|
||||
if (!job.GetValue(repeat_edge_pixels_input_).data.toBool()) {
|
||||
job.SetAlphaChannelRequired(true);
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const
|
||||
|
||||
} else {
|
||||
// If we're not performing the blur job, just push the texture
|
||||
table.Push(job.GetValue(texture_input_));
|
||||
table.Push(job.GetValue(texture_input_), this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,12 +94,12 @@ NodeValueTable StrokeFilterNode::Value(NodeValueDatabase &value) const
|
||||
|
||||
NodeValueTable table = value.Merge();
|
||||
|
||||
if (!job.GetValue(tex_input_).data().isNull()) {
|
||||
if (job.GetValue(radius_input_).data().toDouble() > 0.0
|
||||
&& job.GetValue(opacity_input_).data().toDouble() > 0.0) {
|
||||
if (!job.GetValue(tex_input_).data.isNull()) {
|
||||
if (job.GetValue(radius_input_).data.toDouble() > 0.0
|
||||
&& job.GetValue(opacity_input_).data.toDouble() > 0.0) {
|
||||
table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this);
|
||||
} else {
|
||||
table.Push(job.GetValue(tex_input_));
|
||||
table.Push(job.GetValue(tex_input_), this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ ShaderCode StrokeFilterNode::GetShaderCode(const QString &shader_id) const
|
||||
{
|
||||
Q_UNUSED(shader_id)
|
||||
|
||||
return ShaderCode(ReadFileAsString(":/shaders/stroke.frag"), QString());
|
||||
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/stroke.frag"), QString());
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -89,7 +89,7 @@ ShaderCode PolygonGenerator::GetShaderCode(const QString &shader_id) const
|
||||
{
|
||||
Q_UNUSED(shader_id)
|
||||
|
||||
return ShaderCode(Node::ReadFileAsString(":/shaders/polygon.frag"), QString());
|
||||
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/polygon.frag"), QString());
|
||||
}
|
||||
|
||||
NodeValueTable PolygonGenerator::Value(NodeValueDatabase &value) const
|
||||
|
||||
@@ -77,7 +77,7 @@ ShaderCode SolidGenerator::GetShaderCode(const QString &shader_id) const
|
||||
{
|
||||
Q_UNUSED(shader_id)
|
||||
|
||||
return ShaderCode(ReadFileAsString(":/shaders/solid.frag"), QString());
|
||||
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/solid.frag"), QString());
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -104,7 +104,7 @@ NodeValueTable TextGenerator::Value(NodeValueDatabase &value) const
|
||||
|
||||
NodeValueTable table = value.Merge();
|
||||
|
||||
if (!job.GetValue(text_input_).data().toString().isEmpty()) {
|
||||
if (!job.GetValue(text_input_).data.toString().isEmpty()) {
|
||||
table.Push(NodeParam::kGenerateJob, QVariant::fromValue(job), this);
|
||||
}
|
||||
|
||||
@@ -124,14 +124,14 @@ void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const
|
||||
|
||||
// Set default font
|
||||
QFont default_font;
|
||||
default_font.setFamily(job.GetValue(font_input_).data().toString());
|
||||
default_font.setPointSizeF(job.GetValue(font_size_input_).data().toFloat());
|
||||
default_font.setFamily(job.GetValue(font_input_).data.toString());
|
||||
default_font.setPointSizeF(job.GetValue(font_size_input_).data.toFloat());
|
||||
text_doc.setDefaultFont(default_font);
|
||||
|
||||
// Center by default
|
||||
text_doc.setDefaultTextOption(QTextOption(Qt::AlignCenter));
|
||||
|
||||
text_doc.setHtml(job.GetValue(text_input_).data().toString());
|
||||
text_doc.setHtml(job.GetValue(text_input_).data.toString());
|
||||
|
||||
// Align to 80% width because that's considered the "title safe" area
|
||||
int tenth_of_width = frame->video_params().width() / 10;
|
||||
@@ -144,7 +144,7 @@ void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const
|
||||
// Push 10% inwards to compensate for title safe area
|
||||
p.translate(tenth_of_width, 0);
|
||||
|
||||
TextVerticalAlign valign = static_cast<TextVerticalAlign>(job.GetValue(valign_input_).data().toInt());
|
||||
TextVerticalAlign valign = static_cast<TextVerticalAlign>(job.GetValue(valign_input_).data.toInt());
|
||||
int doc_height = text_doc.size().height();
|
||||
|
||||
switch (valign) {
|
||||
@@ -165,7 +165,7 @@ void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const
|
||||
text_doc.drawContents(&p);
|
||||
|
||||
// Transplant alpha channel to frame
|
||||
Color rgb = job.GetValue(color_input_).data().value<Color>();
|
||||
Color rgb = job.GetValue(color_input_).data.value<Color>();
|
||||
for (int x=0; x<frame->width(); x++) {
|
||||
for (int y=0; y<frame->height(); y++) {
|
||||
uchar src_alpha = img.bits()[img.bytesPerLine() * y + x];
|
||||
|
||||
@@ -48,7 +48,7 @@ ShaderCode MathNodeBase::GetShaderCodeInternal(const QString &shader_id, NodeInp
|
||||
// No-op frag shader (can we return QString() instead?)
|
||||
operation = QStringLiteral("texture(%1, ove_texcoord)").arg(tex_in->id());
|
||||
|
||||
vert = ReadFileAsString(":/shaders/matrix.vert").arg(mat_in->id(), tex_in->id());
|
||||
vert = FileFunctions::ReadFileAsString(":/shaders/matrix.vert").arg(mat_in->id(), tex_in->id());
|
||||
|
||||
} else {
|
||||
switch (op) {
|
||||
@@ -329,7 +329,7 @@ NodeValueTable MathNodeBase::ValueInternal(NodeValueDatabase &value, Operation o
|
||||
float number = RetrieveNumber(number_val);
|
||||
|
||||
SampleJob job(val_a.type() == NodeParam::kSamples ? val_a : val_b);
|
||||
job.InsertValue(number_param, NodeValue(NodeParam::kFloat, number, this));
|
||||
job.InsertValue(number_param, ShaderValue(number, NodeParam::kFloat));
|
||||
|
||||
if (job.HasSamples()) {
|
||||
if (number_param->is_static()) {
|
||||
|
||||
@@ -66,7 +66,7 @@ ShaderCode MergeNode::GetShaderCode(const QString &shader_id) const
|
||||
{
|
||||
Q_UNUSED(shader_id)
|
||||
|
||||
return ShaderCode(ReadFileAsString(":/shaders/alphaover.frag"), QString());
|
||||
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/alphaover.frag"), QString());
|
||||
}
|
||||
|
||||
NodeValueTable MergeNode::Value(NodeValueDatabase &value) const
|
||||
@@ -79,13 +79,13 @@ NodeValueTable MergeNode::Value(NodeValueDatabase &value) const
|
||||
|
||||
NodeValueTable table = value.Merge();
|
||||
|
||||
if (!job.GetValue(base_in_).data().isNull() || !job.GetValue(blend_in_).data().isNull()) {
|
||||
if (job.GetValue(base_in_).data().isNull()) {
|
||||
if (!job.GetValue(base_in_).data.isNull() || !job.GetValue(blend_in_).data.isNull()) {
|
||||
if (job.GetValue(base_in_).data.isNull()) {
|
||||
// We only have a blend texture, no need to alpha over
|
||||
table.Push(job.GetValue(blend_in_));
|
||||
} else if (job.GetValue(blend_in_).data().isNull()) {
|
||||
table.Push(job.GetValue(blend_in_), this);
|
||||
} else if (job.GetValue(blend_in_).data.isNull()) {
|
||||
// We only have a base texture, no need to alpha over
|
||||
table.Push(job.GetValue(base_in_));
|
||||
table.Push(job.GetValue(base_in_), this);
|
||||
} else {
|
||||
// We have both textures, push the job
|
||||
table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this);
|
||||
|
||||
@@ -270,18 +270,6 @@ QList<NodeInput *> Node::GetInputsToHash() const
|
||||
return GetInputsIncludingArrays();
|
||||
}
|
||||
|
||||
QString Node::ReadFileAsString(const QString &filename)
|
||||
{
|
||||
QFile f(filename);
|
||||
QString file_data;
|
||||
if (f.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QTextStream text_stream(&f);
|
||||
file_data = text_stream.readAll();
|
||||
f.close();
|
||||
}
|
||||
return file_data;
|
||||
}
|
||||
|
||||
void GetInputsIncludingArraysInternal(NodeInputArray* array, QList<NodeInput *>& list)
|
||||
{
|
||||
foreach (NodeInput* input, array->sub_params()) {
|
||||
|
||||
@@ -404,8 +404,6 @@ public:
|
||||
|
||||
void SetPosition(const QPointF& pos);
|
||||
|
||||
static QString ReadFileAsString(const QString& filename);
|
||||
|
||||
QList<NodeInput*> GetInputsIncludingArrays() const;
|
||||
|
||||
QList<NodeOutput*> GetOutputs() const;
|
||||
|
||||
@@ -22,26 +22,6 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
NodeValueTable& NodeValueDatabase::operator[](const QString &input_id)
|
||||
{
|
||||
return tables_[input_id];
|
||||
}
|
||||
|
||||
NodeValueTable& NodeValueDatabase::operator[](const NodeInput *input)
|
||||
{
|
||||
return tables_[input->id()];
|
||||
}
|
||||
|
||||
void NodeValueDatabase::Insert(const QString &key, const NodeValueTable &value)
|
||||
{
|
||||
tables_.insert(key, value);
|
||||
}
|
||||
|
||||
void NodeValueDatabase::Insert(const NodeInput *key, const NodeValueTable &value)
|
||||
{
|
||||
tables_.insert(key->id(), value);
|
||||
}
|
||||
|
||||
NodeValueTable NodeValueDatabase::Merge() const
|
||||
{
|
||||
QHash<QString, NodeValueTable> copy = tables_;
|
||||
@@ -103,41 +83,6 @@ NodeValue NodeValueTable::TakeWithMeta(const NodeParam::DataType &type, const QS
|
||||
return NodeValue();
|
||||
}
|
||||
|
||||
void NodeValueTable::Push(const NodeValue &value)
|
||||
{
|
||||
values_.append(value);
|
||||
}
|
||||
|
||||
void NodeValueTable::Push(const NodeParam::DataType &type, const QVariant &data, const Node* from, const QString &tag)
|
||||
{
|
||||
Push(NodeValue(type, data, from, tag));
|
||||
}
|
||||
|
||||
void NodeValueTable::Prepend(const NodeValue &value)
|
||||
{
|
||||
values_.prepend(value);
|
||||
}
|
||||
|
||||
void NodeValueTable::Prepend(const NodeParam::DataType &type, const QVariant &data, const Node* from, const QString &tag)
|
||||
{
|
||||
Prepend(NodeValue(type, data, from, tag));
|
||||
}
|
||||
|
||||
const NodeValue &NodeValueTable::at(int index) const
|
||||
{
|
||||
return values_.at(index);
|
||||
}
|
||||
|
||||
NodeValue NodeValueTable::TakeAt(int index)
|
||||
{
|
||||
return values_.takeAt(index);
|
||||
}
|
||||
|
||||
int NodeValueTable::Count() const
|
||||
{
|
||||
return values_.size();
|
||||
}
|
||||
|
||||
bool NodeValueTable::Has(const NodeParam::DataType &type) const
|
||||
{
|
||||
for (int i=values_.size() - 1;i>=0;i--) {
|
||||
@@ -163,11 +108,6 @@ void NodeValueTable::Remove(const NodeValue &v)
|
||||
}
|
||||
}
|
||||
|
||||
bool NodeValueTable::isEmpty() const
|
||||
{
|
||||
return values_.isEmpty();
|
||||
}
|
||||
|
||||
NodeValueTable NodeValueTable::Merge(QList<NodeValueTable> tables)
|
||||
{
|
||||
|
||||
|
||||
+68
-12
@@ -24,6 +24,7 @@
|
||||
#include <QString>
|
||||
|
||||
#include "input.h"
|
||||
#include "render/shadervalue.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
@@ -72,17 +73,58 @@ public:
|
||||
NodeValue GetWithMeta(const NodeParam::DataType& type, const QString& tag = QString()) const;
|
||||
QVariant Take(const NodeParam::DataType& type, const QString& tag = QString());
|
||||
NodeValue TakeWithMeta(const NodeParam::DataType& type, const QString& tag = QString());
|
||||
void Push(const NodeValue& value);
|
||||
void Push(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString());
|
||||
void Prepend(const NodeValue& value);
|
||||
void Prepend(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString());
|
||||
const NodeValue& at(int index) const;
|
||||
NodeValue TakeAt(int index);
|
||||
int Count() const;
|
||||
|
||||
void Push(const NodeValue& value)
|
||||
{
|
||||
values_.append(value);
|
||||
}
|
||||
|
||||
void Push(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString())
|
||||
{
|
||||
Push(NodeValue(type, data, from, tag));
|
||||
}
|
||||
|
||||
void Push(const ShaderValue &value, const Node *from)
|
||||
{
|
||||
Push(value.type, value.data, from, value.tag);
|
||||
}
|
||||
|
||||
void Prepend(const NodeValue& value)
|
||||
{
|
||||
values_.prepend(value);
|
||||
}
|
||||
|
||||
void Prepend(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString())
|
||||
{
|
||||
Prepend(NodeValue(type, data, from, tag));
|
||||
}
|
||||
|
||||
void Prepend(const ShaderValue &value, const Node *from)
|
||||
{
|
||||
Prepend(value.type, value.data, from, value.tag);
|
||||
}
|
||||
|
||||
const NodeValue& at(int index) const
|
||||
{
|
||||
return values_.at(index);
|
||||
}
|
||||
NodeValue TakeAt(int index)
|
||||
{
|
||||
return values_.takeAt(index);
|
||||
}
|
||||
|
||||
int Count() const
|
||||
{
|
||||
return values_.size();
|
||||
}
|
||||
|
||||
bool Has(const NodeParam::DataType& type) const;
|
||||
void Remove(const NodeValue& v);
|
||||
|
||||
bool isEmpty() const;
|
||||
bool isEmpty() const
|
||||
{
|
||||
return values_.isEmpty();
|
||||
}
|
||||
|
||||
static NodeValueTable Merge(QList<NodeValueTable> tables);
|
||||
|
||||
@@ -98,11 +140,25 @@ class NodeValueDatabase
|
||||
public:
|
||||
NodeValueDatabase() = default;
|
||||
|
||||
NodeValueTable& operator[](const QString& input_id);
|
||||
NodeValueTable& operator[](const NodeInput* input);
|
||||
NodeValueTable& operator[](const QString& input_id)
|
||||
{
|
||||
return tables_[input_id];
|
||||
}
|
||||
|
||||
void Insert(const QString& key, const NodeValueTable &value);
|
||||
void Insert(const NodeInput* key, const NodeValueTable& value);
|
||||
NodeValueTable& operator[](const NodeInput* input)
|
||||
{
|
||||
return tables_[input->id()];
|
||||
}
|
||||
|
||||
void Insert(const QString& key, const NodeValueTable &value)
|
||||
{
|
||||
tables_.insert(key, value);
|
||||
}
|
||||
|
||||
void Insert(const NodeInput* key, const NodeValueTable& value)
|
||||
{
|
||||
tables_.insert(key->id(), value);
|
||||
}
|
||||
|
||||
NodeValueTable Merge() const;
|
||||
|
||||
|
||||
@@ -159,12 +159,6 @@ void VideoStream::set_colorspace(const QString &color)
|
||||
emit ParametersChanged();
|
||||
}
|
||||
|
||||
QString VideoStream::get_colorspace_match_string() const
|
||||
{
|
||||
return QStringLiteral("%1:%2").arg(footage()->project()->color_manager()->GetConfigFilename(),
|
||||
colorspace());
|
||||
}
|
||||
|
||||
void VideoStream::ColorConfigChanged()
|
||||
{
|
||||
ColorManager* color_manager = footage()->project()->color_manager();
|
||||
|
||||
@@ -90,8 +90,6 @@ public:
|
||||
const QString& colorspace(bool default_if_empty = true) const;
|
||||
void set_colorspace(const QString& color);
|
||||
|
||||
QString get_colorspace_match_string() const;
|
||||
|
||||
VideoParams::Interlacing interlacing() const
|
||||
{
|
||||
return interlacing_;
|
||||
|
||||
@@ -30,7 +30,6 @@ set(OLIVE_SOURCES
|
||||
render/colorprocessor.h
|
||||
render/colorprocessorcache.h
|
||||
render/colorprocessor.cpp
|
||||
render/decodercache.h
|
||||
render/diskmanager.h
|
||||
render/diskmanager.cpp
|
||||
render/framehashcache.h
|
||||
@@ -43,12 +42,14 @@ set(OLIVE_SOURCES
|
||||
render/playbackcache.cpp
|
||||
render/previewautocacher.h
|
||||
render/previewautocacher.cpp
|
||||
render/rendercache.h
|
||||
render/rendermanager.h
|
||||
render/rendermanager.cpp
|
||||
render/rendermodes.h
|
||||
render/renderprocessor.h
|
||||
render/renderprocessor.cpp
|
||||
render/shaderinfo.h
|
||||
render/shadervalue.h
|
||||
render/stillimagecache.h
|
||||
render/videoparams.h
|
||||
render/videoparams.cpp
|
||||
|
||||
@@ -140,10 +140,6 @@ void OpenGLRenderer::Destroy()
|
||||
// Delete framebuffer
|
||||
functions_->glDeleteFramebuffers(1, &framebuffer_);
|
||||
|
||||
// Delete all shaders
|
||||
qDeleteAll(shader_cache_);
|
||||
shader_cache_.clear();
|
||||
|
||||
// Delete context if it belongs to us
|
||||
if (context_->parent() == this) {
|
||||
delete context_;
|
||||
@@ -171,8 +167,6 @@ void OpenGLRenderer::AttachTextureAsDestination(Renderer::Texture* texture)
|
||||
GL_TEXTURE_2D,
|
||||
texture->id().value<GLuint>(),
|
||||
0);
|
||||
|
||||
SetViewport(texture->width(), texture->height());
|
||||
}
|
||||
|
||||
void OpenGLRenderer::DetachTextureAsDestination()
|
||||
@@ -221,6 +215,8 @@ QVariant OpenGLRenderer::CreateNativeShader(ShaderCode code)
|
||||
goto error;
|
||||
}
|
||||
|
||||
qDebug() << "Shader created successfully";
|
||||
|
||||
return Node::PtrToValue(program);
|
||||
|
||||
error:
|
||||
@@ -281,51 +277,14 @@ void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int lines
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
|
||||
}
|
||||
|
||||
Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob job, VideoParams params)
|
||||
void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destination, VideoParams destination_params)
|
||||
{
|
||||
// If this node is iterative, we'll pick up which input here
|
||||
GLuint iterative_input = 0;
|
||||
QList<GLuint> textures_to_bind;
|
||||
bool input_textures_have_alpha = false;
|
||||
|
||||
QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), job.GetShaderID());
|
||||
QOpenGLShaderProgram* shader = shader_cache_.value(full_shader_id);
|
||||
|
||||
if (!shader) {
|
||||
// Since we have shader code, compile it now
|
||||
ShaderCode code = node->GetShaderCode(job.GetShaderID());
|
||||
QString vert_code = code.vert_code();
|
||||
QString frag_code = code.frag_code();
|
||||
|
||||
if (frag_code.isEmpty() && vert_code.isEmpty()) {
|
||||
qWarning() << "No shader code found for" << node->id() << "- operation will be a no-op";
|
||||
}
|
||||
|
||||
if (frag_code.isEmpty()) {
|
||||
frag_code = Node::ReadFileAsString(QStringLiteral(":/shaders/default.frag"));
|
||||
}
|
||||
|
||||
if (vert_code.isEmpty()) {
|
||||
vert_code = Node::ReadFileAsString(QStringLiteral(":/shaders/default.vert"));
|
||||
}
|
||||
|
||||
shader = new QOpenGLShaderProgram(this);
|
||||
if (shader
|
||||
&& shader->create()
|
||||
&& shader->addShaderFromSourceCode(QOpenGLShader::Fragment, frag_code)
|
||||
&& shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_code)
|
||||
&& shader->link()) {
|
||||
shader_cache_.insert(full_shader_id, shader);
|
||||
} else {
|
||||
qWarning() << "Failed to compile shader for" << node->id();
|
||||
shader = nullptr;
|
||||
}
|
||||
|
||||
if (!shader) {
|
||||
// Couldn't find or build the shader required
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
QOpenGLShaderProgram* shader = Node::ValueToPtr<QOpenGLShaderProgram>(s);
|
||||
|
||||
shader->bind();
|
||||
|
||||
@@ -338,28 +297,25 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
|
||||
continue;
|
||||
}
|
||||
|
||||
// See if this value corresponds to an input (NOTE: it may not and this may be null)
|
||||
NodeInput* corresponding_input = node->GetInputWithID(it.key());
|
||||
|
||||
// This variable is used in the shader, let's set it
|
||||
const QVariant& value = it.value().data();
|
||||
const ShaderValue& value = it.value();
|
||||
|
||||
NodeParam::DataType data_type = (it.value().type() != NodeParam::kNone)
|
||||
? it.value().type()
|
||||
: corresponding_input->data_type();
|
||||
if (value.array) {
|
||||
qWarning() << "FIXME: Array support is currently a stub";
|
||||
}
|
||||
|
||||
switch (data_type) {
|
||||
switch (value.type) {
|
||||
case NodeInput::kInt:
|
||||
// kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to
|
||||
// over/underflows if the number is large enough, but the likelihood of that is quite low.
|
||||
shader->setUniformValue(variable_location, value.toInt());
|
||||
shader->setUniformValue(variable_location, value.data.toInt());
|
||||
break;
|
||||
case NodeInput::kFloat:
|
||||
// kFloat technically specifies a double but as above, OpenGL doesn't support those.
|
||||
shader->setUniformValue(variable_location, value.toFloat());
|
||||
shader->setUniformValue(variable_location, value.data.toFloat());
|
||||
break;
|
||||
case NodeInput::kVec2:
|
||||
if (corresponding_input && corresponding_input->IsArray()) {
|
||||
/*if (corresponding_input && corresponding_input->IsArray()) {
|
||||
QVector<NodeValue> nv = value.value< QVector<NodeValue> >();
|
||||
QVector<QVector2D> a(nv.size());
|
||||
|
||||
@@ -374,41 +330,42 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
|
||||
shader->setUniformValue(count_location, a.size());
|
||||
}
|
||||
} else {
|
||||
shader->setUniformValue(variable_location, value.value<QVector2D>());
|
||||
}
|
||||
|
||||
}*/
|
||||
shader->setUniformValue(variable_location, value.data.value<QVector2D>());
|
||||
break;
|
||||
case NodeInput::kVec3:
|
||||
shader->setUniformValue(variable_location, value.value<QVector3D>());
|
||||
shader->setUniformValue(variable_location, value.data.value<QVector3D>());
|
||||
break;
|
||||
case NodeInput::kVec4:
|
||||
shader->setUniformValue(variable_location, value.value<QVector4D>());
|
||||
shader->setUniformValue(variable_location, value.data.value<QVector4D>());
|
||||
break;
|
||||
case NodeInput::kMatrix:
|
||||
shader->setUniformValue(variable_location, value.value<QMatrix4x4>());
|
||||
shader->setUniformValue(variable_location, value.data.value<QMatrix4x4>());
|
||||
break;
|
||||
case NodeInput::kCombo:
|
||||
shader->setUniformValue(variable_location, value.value<int>());
|
||||
shader->setUniformValue(variable_location, value.data.value<int>());
|
||||
break;
|
||||
case NodeInput::kColor:
|
||||
{
|
||||
Color color = value.value<Color>();
|
||||
Color color = value.data.value<Color>();
|
||||
|
||||
shader->setUniformValue(variable_location, color.red(), color.green(), color.blue(), color.alpha());
|
||||
break;
|
||||
}
|
||||
case NodeInput::kBoolean:
|
||||
shader->setUniformValue(variable_location, value.toBool());
|
||||
shader->setUniformValue(variable_location, value.data.toBool());
|
||||
break;
|
||||
case NodeInput::kBuffer:
|
||||
case NodeInput::kTexture:
|
||||
{
|
||||
TexturePtr texture = value.value<TexturePtr>();
|
||||
TexturePtr texture = value.data.value<TexturePtr>();
|
||||
|
||||
// Set value to bound texture
|
||||
shader->setUniformValue(variable_location, textures_to_bind.size());
|
||||
|
||||
// If this texture binding is the iterative input, set it here
|
||||
if (corresponding_input && corresponding_input == job.GetIterativeInput()) {
|
||||
if (it.key() == job.GetIterativeInput()) {
|
||||
iterative_input = textures_to_bind.size();
|
||||
}
|
||||
|
||||
@@ -434,8 +391,8 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
|
||||
|
||||
// Adjust virtual width by pixel aspect if necessary
|
||||
if (texture->params().pixel_aspect_ratio() != 1
|
||||
|| params.pixel_aspect_ratio() != 1) {
|
||||
double relative_pixel_aspect = texture->params().pixel_aspect_ratio().toDouble() / params.pixel_aspect_ratio().toDouble();
|
||||
|| destination_params.pixel_aspect_ratio() != 1) {
|
||||
double relative_pixel_aspect = texture->params().pixel_aspect_ratio().toDouble() / destination_params.pixel_aspect_ratio().toDouble();
|
||||
|
||||
adjusted_width = qRound(static_cast<double>(adjusted_width) * relative_pixel_aspect);
|
||||
}
|
||||
@@ -466,32 +423,13 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
|
||||
}
|
||||
}
|
||||
|
||||
// Provide some standard args
|
||||
// Set ove_resolution to the destination to the "logical" resolution of the destination
|
||||
shader->setUniformValue("ove_resolution",
|
||||
static_cast<GLfloat>(params.width()),
|
||||
static_cast<GLfloat>(params.height()));
|
||||
static_cast<GLfloat>(destination_params.width()),
|
||||
static_cast<GLfloat>(destination_params.height()));
|
||||
|
||||
// Create the output textures
|
||||
int real_iteration_count;
|
||||
if (job.GetIterationCount() > 1 && job.GetIterativeInput()) {
|
||||
real_iteration_count = job.GetIterationCount();
|
||||
} else {
|
||||
real_iteration_count = 1;
|
||||
}
|
||||
|
||||
TexturePtr dst_refs[2];
|
||||
dst_refs[0] = CreateTexture(params);
|
||||
|
||||
// If this node requires multiple iterations, get a texture for it too
|
||||
if (real_iteration_count > 1) {
|
||||
dst_refs[1] = CreateTexture(params);
|
||||
}
|
||||
|
||||
// Some nodes use multiple iterations for optimization
|
||||
TexturePtr input_tex, output_tex;
|
||||
|
||||
// Set up OpenGL parameters as necessary
|
||||
functions_->glViewport(0, 0, params.effective_width(), params.effective_height());
|
||||
// Set the viewport to the "physical" resolution of the destination
|
||||
functions_->glViewport(0, 0, destination_params.effective_width(), destination_params.effective_height());
|
||||
|
||||
// Bind all textures
|
||||
for (int i=0; i<textures_to_bind.size(); i++) {
|
||||
@@ -516,30 +454,71 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
|
||||
functions_->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
|
||||
frag_vbo_.release();
|
||||
|
||||
// Some shaders optimize through multiple iterations which requires ping-ponging textures
|
||||
// - If there are only two iterations, we can just create one backend texture and then the
|
||||
// destination can be the second
|
||||
// - If there are more than two iterations, we need to ping pong back and forth between two
|
||||
// textures. We can still use the destination as the last iteration, but we'll need textures
|
||||
// for the iterative process.
|
||||
int real_iteration_count;
|
||||
if (job.GetIterationCount() > 1 && !job.GetIterativeInput().isEmpty()) {
|
||||
real_iteration_count = job.GetIterationCount();
|
||||
} else {
|
||||
real_iteration_count = 1;
|
||||
}
|
||||
|
||||
TexturePtr output_tex, input_tex;
|
||||
if (real_iteration_count > 1) {
|
||||
// Create one texture to bounce off
|
||||
output_tex = CreateTexture(destination_params);
|
||||
|
||||
if (real_iteration_count > 2) {
|
||||
// Create a second texture bounce off
|
||||
input_tex = CreateTexture(destination_params);
|
||||
}
|
||||
}
|
||||
|
||||
for (int iteration=0; iteration<real_iteration_count; iteration++) {
|
||||
// Set iteration number
|
||||
shader->setUniformValue("ove_iteration", iteration);
|
||||
|
||||
// Replace iterative input
|
||||
if (iteration == 0) {
|
||||
output_tex = dst_refs[0];
|
||||
if (iteration == real_iteration_count-1) {
|
||||
// This is the last iteration, draw to the destination
|
||||
if (destination) {
|
||||
// If we have a destination texture, draw to it
|
||||
AttachTextureAsDestination(destination);
|
||||
} else if (iteration > 0) {
|
||||
// Otherwise, if we were iterating before, detach texture now
|
||||
DetachTextureAsDestination();
|
||||
}
|
||||
} else {
|
||||
input_tex = dst_refs[(iteration+1)%2];
|
||||
output_tex = dst_refs[iteration%2];
|
||||
// Always draw to output_tex
|
||||
AttachTextureAsDestination(output_tex.get());
|
||||
|
||||
functions_->glActiveTexture(GL_TEXTURE0 + iterative_input);
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, input_tex->id().value<GLuint>());
|
||||
PrepareInputTexture(job.GetBilinearFiltering());
|
||||
if (iteration > 0) {
|
||||
// If this is not the first iteration, replace the iterative texture with the one we
|
||||
// last drew
|
||||
functions_->glActiveTexture(GL_TEXTURE0 + iterative_input);
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, input_tex->id().value<GLuint>());
|
||||
PrepareInputTexture(job.GetBilinearFiltering());
|
||||
}
|
||||
|
||||
// Swap so that the next iteration, the texture we draw now will be the input texture next
|
||||
std::swap(output_tex, input_tex);
|
||||
}
|
||||
|
||||
AttachTextureAsDestination(output_tex.get());
|
||||
|
||||
// Blit this texture through this shader
|
||||
functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3);
|
||||
}
|
||||
|
||||
// Reset framebuffer to default
|
||||
DetachTextureAsDestination();
|
||||
if (destination) {
|
||||
// Reset framebuffer to default if we were drawing to a texture
|
||||
DetachTextureAsDestination();
|
||||
|
||||
// Set metadata for whether this texture has a meaningful alpha channel
|
||||
destination->set_has_meaningful_alpha((input_textures_have_alpha || job.GetAlphaChannelRequired()));
|
||||
}
|
||||
|
||||
// Release any textures we bound before
|
||||
for (int i=textures_to_bind.size()-1; i>=0; i--) {
|
||||
@@ -552,23 +531,9 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
|
||||
|
||||
// Release shader
|
||||
shader->release();
|
||||
|
||||
output_tex->set_has_meaningful_alpha((input_textures_have_alpha || job.GetAlphaChannelRequired()));
|
||||
|
||||
return output_tex;
|
||||
}
|
||||
|
||||
void OpenGLRenderer::SetViewport(int width, int height)
|
||||
{
|
||||
functions_->glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::BlitColorManaged(ColorProcessorPtr color_processor, Texture *source, Renderer::Texture* destination)
|
||||
{
|
||||
qCritical() << "OpenGLRenderer::BlitColorMangaed is a stub!";
|
||||
}
|
||||
|
||||
void OpenGLRenderer::Blit(Renderer::Texture *source, QVariant shader, Renderer::ShaderUniformMap parameters, Renderer::Texture *destination)
|
||||
/*void OpenGLRenderer::Blit(Renderer::Texture *source, QVariant shader, Renderer::ShaderUniformMap parameters, Renderer::Texture *destination)
|
||||
{
|
||||
QOpenGLShaderProgram* program = Node::ValueToPtr<QOpenGLShaderProgram>(shader);
|
||||
|
||||
@@ -594,7 +559,7 @@ void OpenGLRenderer::Blit(Renderer::Texture *source, QVariant shader, Renderer::
|
||||
if (destination) {
|
||||
DetachTextureAsDestination();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format)
|
||||
{
|
||||
|
||||
@@ -51,10 +51,6 @@ public slots:
|
||||
|
||||
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
|
||||
|
||||
virtual void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture) override;
|
||||
|
||||
virtual void DetachTextureAsDestination() override;
|
||||
|
||||
virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) override;
|
||||
|
||||
virtual void DestroyNativeTexture(QVariant texture) override;
|
||||
@@ -67,21 +63,21 @@ public slots:
|
||||
|
||||
virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) override;
|
||||
|
||||
virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node,
|
||||
OLIVE_NAMESPACE::ShaderJob job,
|
||||
OLIVE_NAMESPACE::VideoParams params) override;
|
||||
|
||||
virtual void SetViewport(int width, int height) override;
|
||||
|
||||
virtual void BlitColorManaged(OLIVE_NAMESPACE::ColorProcessorPtr color_processor, OLIVE_NAMESPACE::Renderer::Texture* source, OLIVE_NAMESPACE::Renderer::Texture *destination = nullptr) override;
|
||||
|
||||
virtual void Blit(OLIVE_NAMESPACE::Renderer::Texture* source, QVariant shader, OLIVE_NAMESPACE::Renderer::ShaderUniformMap parameters, OLIVE_NAMESPACE::Renderer::Texture* destination = nullptr) override;
|
||||
protected slots:
|
||||
virtual void Blit(QVariant shader,
|
||||
OLIVE_NAMESPACE::ShaderJob job,
|
||||
OLIVE_NAMESPACE::Renderer::Texture* destination,
|
||||
OLIVE_NAMESPACE::VideoParams destination_params) override;
|
||||
|
||||
private:
|
||||
static GLint GetInternalFormat(PixelFormat::Format format);
|
||||
|
||||
static GLenum GetPixelType(PixelFormat::Format format);
|
||||
|
||||
void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture);
|
||||
|
||||
void DetachTextureAsDestination();
|
||||
|
||||
void PrepareInputTexture(bool bilinear);
|
||||
|
||||
QOpenGLContext* context_;
|
||||
@@ -98,8 +94,6 @@ private:
|
||||
|
||||
GLuint framebuffer_;
|
||||
|
||||
QHash<QString, QOpenGLShaderProgram*> shader_cache_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
|
||||
#include "renderer.h"
|
||||
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
|
||||
#include <QFloat16>
|
||||
|
||||
#include "render/colormanager.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
Renderer::Renderer(QObject *parent) :
|
||||
@@ -39,4 +46,91 @@ Renderer::TexturePtr Renderer::CreateTexture(const VideoParams ¶m, void *dat
|
||||
return std::make_shared<Texture>(this, v, param);
|
||||
}
|
||||
|
||||
// copied from source code to OCIODisplay
|
||||
/*const int OCIO_LUT3D_EDGE_SIZE = 64;
|
||||
|
||||
const int OCIO_LUT3D_PIXEL_COUNT = OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE;
|
||||
const int OCIO_LUT3D_ENTRY_COUNT = 3 * OCIO_LUT3D_PIXEL_COUNT;
|
||||
const int OCIO_LUT3D_ENTRY_COUNT_WITH_ALPHA = 4 * OCIO_LUT3D_PIXEL_COUNT;
|
||||
const int OCIO_LUT2D_EDGE_SIZE = 512;*/
|
||||
|
||||
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture *destination)
|
||||
{
|
||||
/*ColorContext color_ctx;
|
||||
|
||||
if (color_cache_.contains(color_processor->id())) {
|
||||
color_ctx = color_cache_.value(color_processor->id());
|
||||
} else {
|
||||
// Generate OCIO color context
|
||||
|
||||
// Generate OCIO shader descriptor
|
||||
const char* ocio_func_name = "OCIODisplay";
|
||||
OCIO::GpuShaderDesc shader_desc;
|
||||
shader_desc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
|
||||
shader_desc.setFunctionName(ocio_func_name);
|
||||
shader_desc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE);
|
||||
|
||||
// Generate LUT
|
||||
QVector<float> lut_data(OCIO_LUT3D_ENTRY_COUNT);
|
||||
color_processor->GetProcessor()->getGpuLut3D(lut_data.data(), shader_desc);
|
||||
|
||||
// Convert to half float RGBA
|
||||
QVector<qfloat16> texture_ready_lut_data(OCIO_LUT3D_ENTRY_COUNT_WITH_ALPHA);
|
||||
for (int i=0; i<OCIO_LUT3D_PIXEL_COUNT; i++) {
|
||||
texture_ready_lut_data[i*kRGBAChannels+0] = lut_data[i*kRGBChannels+0];
|
||||
texture_ready_lut_data[i*kRGBAChannels+1] = lut_data[i*kRGBChannels+1];
|
||||
texture_ready_lut_data[i*kRGBAChannels+2] = lut_data[i*kRGBChannels+2];
|
||||
texture_ready_lut_data[i*kRGBAChannels+3] = 1.0f;
|
||||
}
|
||||
|
||||
// Create LUT texture
|
||||
color_ctx.lut = CreateTexture(VideoParams(OCIO_LUT2D_EDGE_SIZE, OCIO_LUT2D_EDGE_SIZE, PixelFormat::PIX_FMT_RGBA32F),
|
||||
texture_ready_lut_data.data());
|
||||
|
||||
// Create shader
|
||||
QString frag_code;
|
||||
|
||||
frag_code.append(QStringLiteral("sampler2D texture;\n"
|
||||
"sampler2D lut;\n"
|
||||
"\n"
|
||||
"vec3 LUTLookup(sampler2D lut3d, vec3 in_coord)\n"
|
||||
"{\n"
|
||||
" return texture2D(lut3d, vec2());\n"
|
||||
"}\n"
|
||||
"\n"));
|
||||
|
||||
// Correct code for our GLSL set up
|
||||
QString ocio_code = color_processor->GetProcessor()->getGpuShaderText(shader_desc);
|
||||
ocio_code.replace(QStringLiteral("texture3D"), QStringLiteral("texture2D"));
|
||||
ocio_code.replace(QStringLiteral("sampler3D"), QStringLiteral("sampler2D"));
|
||||
|
||||
|
||||
|
||||
qDebug() << frag_code;
|
||||
|
||||
//qDebug() << "FIXME: GPU doesn't handle associated alpha yet";
|
||||
}*/
|
||||
|
||||
qDebug() << "BlitColorManaged is a partial stub";
|
||||
|
||||
QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert")));
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture));
|
||||
|
||||
BlitToTexture(shader, job, destination);
|
||||
}
|
||||
|
||||
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params)
|
||||
{
|
||||
qDebug() << "BlitColorManaged is a partial stub";
|
||||
|
||||
QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert")));
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture));
|
||||
|
||||
Blit(shader, job, params);
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -121,12 +121,22 @@ public:
|
||||
|
||||
TexturePtr CreateTexture(const VideoParams& param, void* data = nullptr, int linesize = 0);
|
||||
|
||||
struct ShaderValue {
|
||||
QVariant data;
|
||||
NodeParam::DataType type;
|
||||
};
|
||||
void BlitToTexture(QVariant shader,
|
||||
OLIVE_NAMESPACE::ShaderJob job,
|
||||
OLIVE_NAMESPACE::Renderer::Texture* destination)
|
||||
{
|
||||
Blit(shader, job, destination, destination->params());
|
||||
}
|
||||
|
||||
using ShaderUniformMap = QHash<QString, ShaderValue>;
|
||||
void Blit(QVariant shader,
|
||||
OLIVE_NAMESPACE::ShaderJob job,
|
||||
OLIVE_NAMESPACE::VideoParams params)
|
||||
{
|
||||
Blit(shader, job, nullptr, params);
|
||||
}
|
||||
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture* destination);
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params);
|
||||
|
||||
public slots:
|
||||
virtual void PostInit() = 0;
|
||||
@@ -135,10 +145,6 @@ public slots:
|
||||
|
||||
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) = 0;
|
||||
|
||||
virtual void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture) = 0;
|
||||
|
||||
virtual void DetachTextureAsDestination() = 0;
|
||||
|
||||
virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) = 0;
|
||||
|
||||
virtual void DestroyNativeTexture(QVariant texture) = 0;
|
||||
@@ -151,18 +157,19 @@ public slots:
|
||||
|
||||
virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) = 0;
|
||||
|
||||
virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node,
|
||||
OLIVE_NAMESPACE::ShaderJob job,
|
||||
OLIVE_NAMESPACE::VideoParams params) = 0;
|
||||
|
||||
virtual void SetViewport(int width, int height) = 0;
|
||||
|
||||
virtual void BlitColorManaged(OLIVE_NAMESPACE::ColorProcessorPtr color_processor, OLIVE_NAMESPACE::Renderer::Texture* source, OLIVE_NAMESPACE::Renderer::Texture *destination = nullptr) = 0;
|
||||
|
||||
virtual void Blit(OLIVE_NAMESPACE::Renderer::Texture* source, QVariant shader, OLIVE_NAMESPACE::Renderer::ShaderUniformMap parameters, OLIVE_NAMESPACE::Renderer::Texture* destination = nullptr) = 0;
|
||||
protected slots:
|
||||
virtual void Blit(QVariant shader,
|
||||
OLIVE_NAMESPACE::ShaderJob job,
|
||||
OLIVE_NAMESPACE::Renderer::Texture* destination,
|
||||
OLIVE_NAMESPACE::VideoParams destination_params) = 0;
|
||||
|
||||
private:
|
||||
struct ColorContext {
|
||||
QVariant shader;
|
||||
TexturePtr lut;
|
||||
};
|
||||
|
||||
QHash<QString, ColorContext> color_cache_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -76,17 +76,6 @@ void RendererThreadWrapper::ClearDestination(double r, double g, double b, doubl
|
||||
Q_ARG(double, a));
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::AttachTextureAsDestination(Renderer::Texture *texture)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "AttachTextureAsDestination", Qt::BlockingQueuedConnection,
|
||||
OLIVE_NS_ARG(Renderer::Texture*, texture));
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::DetachTextureAsDestination()
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "DetachTextureAsDestination", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
QVariant RendererThreadWrapper::CreateNativeTexture(VideoParams param, void *data, int linesize)
|
||||
{
|
||||
QVariant v;
|
||||
@@ -139,41 +128,15 @@ void RendererThreadWrapper::DownloadFromTexture(Renderer::Texture *texture, void
|
||||
Q_ARG(int, linesize));
|
||||
}
|
||||
|
||||
Renderer::TexturePtr RendererThreadWrapper::ProcessShader(const Node *node, ShaderJob job, VideoParams params)
|
||||
void RendererThreadWrapper::Blit(QVariant shader, ShaderJob job, Renderer::Texture *destination, VideoParams destination_params)
|
||||
{
|
||||
Renderer::TexturePtr tex;
|
||||
|
||||
QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection,
|
||||
OLIVE_NS_RETURN_ARG(Renderer::TexturePtr, tex),
|
||||
OLIVE_NS_CONST_ARG(Node*, node),
|
||||
OLIVE_NS_ARG(ShaderJob, job),
|
||||
OLIVE_NS_ARG(VideoParams, params));
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::SetViewport(int width, int height)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "SetViewport", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(int, width),
|
||||
Q_ARG(int, height));
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::BlitColorManaged(ColorProcessorPtr color_processor, Renderer::Texture *source, Renderer::Texture *destination)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "BlitColorManaged", Qt::BlockingQueuedConnection,
|
||||
OLIVE_NS_ARG(ColorProcessorPtr, color_processor),
|
||||
OLIVE_NS_ARG(Renderer::Texture*, source),
|
||||
OLIVE_NS_ARG(Renderer::Texture*, destination));
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::Blit(Renderer::Texture *source, QVariant shader, Renderer::ShaderUniformMap parameters, Renderer::Texture *destination)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection,
|
||||
OLIVE_NS_ARG(Renderer::Texture*, source),
|
||||
Q_ARG(QVariant, shader),
|
||||
Q_ARG(Renderer::ShaderUniformMap, parameters),
|
||||
OLIVE_NS_ARG(Renderer::Texture*, destination));
|
||||
OLIVE_NS_ARG(ShaderJob, job),
|
||||
OLIVE_NS_ARG(Renderer::Texture*, destination),
|
||||
OLIVE_NS_ARG(VideoParams, destination_params));
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -47,10 +47,6 @@ public slots:
|
||||
|
||||
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
|
||||
|
||||
virtual void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture) override;
|
||||
|
||||
virtual void DetachTextureAsDestination() override;
|
||||
|
||||
virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) override;
|
||||
|
||||
virtual void DestroyNativeTexture(QVariant texture) override;
|
||||
@@ -63,15 +59,11 @@ public slots:
|
||||
|
||||
virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) override;
|
||||
|
||||
virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node,
|
||||
OLIVE_NAMESPACE::ShaderJob job,
|
||||
OLIVE_NAMESPACE::VideoParams params) override;
|
||||
|
||||
virtual void SetViewport(int width, int height) override;
|
||||
|
||||
virtual void BlitColorManaged(OLIVE_NAMESPACE::ColorProcessorPtr color_processor, OLIVE_NAMESPACE::Renderer::Texture* source, OLIVE_NAMESPACE::Renderer::Texture *destination = nullptr) override;
|
||||
|
||||
virtual void Blit(OLIVE_NAMESPACE::Renderer::Texture* source, QVariant shader, OLIVE_NAMESPACE::Renderer::ShaderUniformMap parameters, OLIVE_NAMESPACE::Renderer::Texture* destination = nullptr) override;
|
||||
protected slots:
|
||||
virtual void Blit(QVariant shader,
|
||||
OLIVE_NAMESPACE::ShaderJob job,
|
||||
OLIVE_NAMESPACE::Renderer::Texture* destination,
|
||||
OLIVE_NAMESPACE::VideoParams destination_params) override;
|
||||
|
||||
private:
|
||||
Renderer* inner_;
|
||||
|
||||
@@ -54,6 +54,8 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const
|
||||
output.toUtf8());
|
||||
|
||||
}
|
||||
|
||||
id_ = GenerateID(config, input, transform);
|
||||
}
|
||||
|
||||
void ColorProcessor::ConvertFrame(Frame *f)
|
||||
@@ -75,6 +77,15 @@ Color ColorProcessor::ConvertColor(Color in)
|
||||
return in;
|
||||
}
|
||||
|
||||
QString ColorProcessor::GenerateID(ColorManager *config, const QString &input, const ColorTransform &transform)
|
||||
{
|
||||
return QStringLiteral("%1:%2:%3:%4:%5").arg(config->GetConfigFilename(),
|
||||
input,
|
||||
transform.display(),
|
||||
transform.view(),
|
||||
transform.look());
|
||||
}
|
||||
|
||||
ColorProcessorPtr ColorProcessor::Create(ColorManager *config, const QString& input, const ColorTransform &transform)
|
||||
{
|
||||
return std::make_shared<ColorProcessor>(config, input, transform);
|
||||
|
||||
@@ -53,9 +53,18 @@ public:
|
||||
|
||||
Color ConvertColor(Color in);
|
||||
|
||||
const QString& id() const
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
|
||||
static QString GenerateID(ColorManager* config, const QString& input, const ColorTransform& dest_space);
|
||||
|
||||
private:
|
||||
OCIO::ConstProcessorRcPtr processor_;
|
||||
|
||||
QString id_;
|
||||
|
||||
};
|
||||
|
||||
using ColorProcessorChain = QList<ColorProcessorPtr>;
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define COLORTRANSFORM_H
|
||||
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
|
||||
#include <QString>
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ PreviewAutoCacher::PreviewAutoCacher() :
|
||||
last_update_time_(0),
|
||||
ignore_next_mouse_button_(false),
|
||||
video_params_changed_(false),
|
||||
audio_params_changed_(false)
|
||||
audio_params_changed_(false),
|
||||
color_manager_(nullptr)
|
||||
{
|
||||
// Set default autocache range
|
||||
SetPlayhead(rational());
|
||||
@@ -582,7 +583,7 @@ void PreviewAutoCacher::TryRender()
|
||||
single_frame_render_->Start();
|
||||
|
||||
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_,
|
||||
static_cast<Sequence*>(viewer_node_->parent())->project()->color_manager(),
|
||||
color_manager_,
|
||||
single_frame_render_->property("time").value<rational>(),
|
||||
RenderMode::kOffline, true));
|
||||
|
||||
@@ -624,7 +625,7 @@ void PreviewAutoCacher::RequeueFrames()
|
||||
connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::VideoRendered);
|
||||
video_tasks_.insert(watcher, hash);
|
||||
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_,
|
||||
static_cast<Sequence*>(viewer_node_->parent())->project()->color_manager(),
|
||||
color_manager_,
|
||||
t, RenderMode::kOffline, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "config/config.h"
|
||||
#include "node/node.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
#include "render/colormanager.h"
|
||||
#include "threading/threadticketwatcher.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
@@ -83,6 +84,11 @@ public:
|
||||
void ClearAudioQueue(bool wait = false);
|
||||
void ClearVideoDownloadQueue(bool wait = false);
|
||||
|
||||
void SetColorManager(ColorManager* manager)
|
||||
{
|
||||
color_manager_ = manager;
|
||||
}
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Main handler for when the NodeGraph changes
|
||||
@@ -148,6 +154,8 @@ private:
|
||||
|
||||
bool audio_params_changed_;
|
||||
|
||||
ColorManager* color_manager_;
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Handler for when the NodeGraph reports a video change over a certain time range
|
||||
|
||||
@@ -18,15 +18,16 @@
|
||||
|
||||
***/
|
||||
|
||||
#ifndef DECODERCACHE_H
|
||||
#define DECODERCACHE_H
|
||||
#ifndef RENDERCACHE_H
|
||||
#define RENDERCACHE_H
|
||||
|
||||
#include "codec/decoder.h"
|
||||
#include "project/item/footage/stream.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class DecoderCache : public QHash<Stream*, DecoderPtr>
|
||||
template <typename K, typename V>
|
||||
class RenderCache : public QHash<K, V>
|
||||
{
|
||||
public:
|
||||
QMutex *mutex()
|
||||
@@ -39,6 +40,9 @@ private:
|
||||
|
||||
};
|
||||
|
||||
using DecoderCache = RenderCache<Stream*, DecoderPtr>;
|
||||
using ShaderCache = RenderCache<QString, QVariant>;
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // DECODERCACHE_H
|
||||
#endif // RENDERCACHE_H
|
||||
@@ -55,6 +55,7 @@ RenderManager::RenderManager(QObject *parent) :
|
||||
|
||||
still_cache_ = new StillImageCache();
|
||||
decoder_cache_ = new DecoderCache();
|
||||
shader_cache_ = new ShaderCache();
|
||||
} else {
|
||||
qCritical() << "Tried to initialize unknown graphics backend";
|
||||
still_cache_ = nullptr;
|
||||
@@ -64,6 +65,7 @@ RenderManager::RenderManager(QObject *parent) :
|
||||
|
||||
RenderManager::~RenderManager()
|
||||
{
|
||||
delete shader_cache_;
|
||||
delete decoder_cache_;
|
||||
delete still_cache_;
|
||||
|
||||
@@ -162,7 +164,7 @@ RenderTicketPtr RenderManager::SaveFrameToCache(FrameHashCache *cache, FramePtr
|
||||
|
||||
void RenderManager::RunTicket(RenderTicketPtr ticket) const
|
||||
{
|
||||
RenderProcessor::Process(ticket, context_, still_cache_, decoder_cache_);
|
||||
RenderProcessor::Process(ticket, context_, still_cache_, decoder_cache_, shader_cache_);
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
#include "config/config.h"
|
||||
#include "colorprocessorcache.h"
|
||||
#include "dialog/rendercancel/rendercancel.h"
|
||||
#include "decodercache.h"
|
||||
#include "node/graph.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
#include "node/traverser.h"
|
||||
#include "render/backend/renderer.h"
|
||||
#include "rendercache.h"
|
||||
#include "stillimagecache.h"
|
||||
#include "threading/threadpool.h"
|
||||
|
||||
@@ -127,6 +127,8 @@ private:
|
||||
|
||||
DecoderCache* decoder_cache_;
|
||||
|
||||
ShaderCache* shader_cache_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -29,11 +29,12 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache) :
|
||||
RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache *shader_cache) :
|
||||
ticket_(ticket),
|
||||
render_ctx_(render_ctx),
|
||||
still_image_cache_(still_image_cache),
|
||||
decoder_cache_(decoder_cache)
|
||||
decoder_cache_(decoder_cache),
|
||||
shader_cache_(shader_cache)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -137,9 +138,9 @@ DecoderPtr RenderProcessor::ResolveDecoderFromInput(StreamPtr stream)
|
||||
return decoder;
|
||||
}
|
||||
|
||||
void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache *still_image_cache, DecoderCache *decoder_cache)
|
||||
void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache *still_image_cache, DecoderCache *decoder_cache, ShaderCache *shader_cache)
|
||||
{
|
||||
RenderProcessor p(ticket, render_ctx, still_image_cache, decoder_cache);
|
||||
RenderProcessor p(ticket, render_ctx, still_image_cache, decoder_cache, shader_cache);
|
||||
p.Run();
|
||||
}
|
||||
|
||||
@@ -228,9 +229,10 @@ QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &
|
||||
// to optimize such a situation
|
||||
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(stream);
|
||||
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
|
||||
|
||||
StillImageCache::Entry want_entry = {nullptr,
|
||||
stream,
|
||||
video_stream->get_colorspace_match_string(),
|
||||
ColorProcessor::GenerateID(Node::ValueToPtr<ColorManager>(ticket_->property("colormanager")), video_stream->colorspace(), ColorTransform(OCIO::ROLE_SCENE_LINEAR)),
|
||||
video_stream->premultiplied_alpha(),
|
||||
video_params.divider(),
|
||||
(video_stream->video_type() == VideoStream::kVideoTypeStill) ? 0 : input_time};
|
||||
@@ -293,14 +295,14 @@ QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &
|
||||
managed_params.set_format(video_params.format());
|
||||
value = render_ctx_->CreateTexture(managed_params);
|
||||
|
||||
// FIXME: Accessing video_stream->colorspace()
|
||||
qDebug() << "FIXME: Accessing video_stream->colorspace() may cause race conditions";
|
||||
|
||||
ColorManager* color_manager = video_stream->footage()->project()->color_manager();
|
||||
ColorProcessorPtr processor = ColorProcessor::Create(color_manager,
|
||||
video_stream->colorspace(),
|
||||
ColorTransform(OCIO::ROLE_SCENE_LINEAR));
|
||||
|
||||
render_ctx_->BlitColorManaged(processor, unmanaged_texture.get(), value.get());
|
||||
render_ctx_->BlitColorManaged(processor, unmanaged_texture, value.get());
|
||||
|
||||
still_image_cache_->mutex()->lock();
|
||||
|
||||
@@ -341,9 +343,30 @@ QVariant RenderProcessor::ProcessShader(const Node *node, const TimeRange &range
|
||||
{
|
||||
Q_UNUSED(range)
|
||||
|
||||
QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), job.GetShaderID());
|
||||
|
||||
QMutexLocker locker(shader_cache_->mutex());
|
||||
|
||||
QVariant shader = shader_cache_->value(full_shader_id);
|
||||
|
||||
if (shader.isNull()) {
|
||||
// Since we have shader code, compile it now
|
||||
shader = render_ctx_->CreateNativeShader(node->GetShaderCode(job.GetShaderID()));
|
||||
|
||||
if (shader.isNull()) {
|
||||
// Couldn't find or build the shader required
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
|
||||
|
||||
return QVariant::fromValue(render_ctx_->ProcessShader(node, job, video_params));
|
||||
Renderer::TexturePtr destination = render_ctx_->CreateTexture(video_params);
|
||||
|
||||
// Run shader
|
||||
render_ctx_->BlitToTexture(shader, job, destination.get());
|
||||
|
||||
return QVariant::fromValue(destination);
|
||||
}
|
||||
|
||||
QVariant RenderProcessor::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job)
|
||||
@@ -372,7 +395,7 @@ QVariant RenderProcessor::ProcessSamples(const Node *node, const TimeRange &rang
|
||||
if (corresponding_input) {
|
||||
value = ProcessInput(corresponding_input, TimeRange(this_sample_time, this_sample_time));
|
||||
} else {
|
||||
value.Push(j.value());
|
||||
value.Push(j.value(), node);
|
||||
}
|
||||
|
||||
value_db.Insert(j.key(), value);
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#ifndef RENDERPROCESSOR_H
|
||||
#define RENDERPROCESSOR_H
|
||||
|
||||
#include "decodercache.h"
|
||||
#include "node/traverser.h"
|
||||
#include "render/backend/renderer.h"
|
||||
#include "rendercache.h"
|
||||
#include "stillimagecache.h"
|
||||
#include "threading/threadticket.h"
|
||||
|
||||
@@ -32,7 +32,7 @@ OLIVE_NAMESPACE_ENTER
|
||||
class RenderProcessor : public NodeTraverser
|
||||
{
|
||||
public:
|
||||
static void Process(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache);
|
||||
static void Process(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache* shader_cache);
|
||||
|
||||
struct RenderedWaveform {
|
||||
const TrackOutput* track;
|
||||
@@ -56,7 +56,7 @@ protected:
|
||||
virtual QVariant GetCachedFrame(const Node *node, const rational &time) override;
|
||||
|
||||
private:
|
||||
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache);
|
||||
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache* shader_cache);
|
||||
|
||||
void Run();
|
||||
|
||||
@@ -70,6 +70,8 @@ private:
|
||||
|
||||
DecoderCache* decoder_cache_;
|
||||
|
||||
ShaderCache* shader_cache_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
+43
-14
@@ -2,56 +2,73 @@
|
||||
#define SHADERINFO_H
|
||||
|
||||
#include "codec/samplebuffer.h"
|
||||
#include "common/filefunctions.h"
|
||||
#include "node/input.h"
|
||||
#include "node/inputarray.h"
|
||||
#include "node/value.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
using NodeValueMap = QHash<QString, NodeValue>;
|
||||
using NodeValueMap = QHash<QString, ShaderValue>;
|
||||
|
||||
class AcceleratedJob {
|
||||
public:
|
||||
AcceleratedJob() = default;
|
||||
|
||||
NodeValue GetValue(NodeInput* input) const
|
||||
ShaderValue GetValue(NodeInput* input) const
|
||||
{
|
||||
return value_map_.value(input->id());
|
||||
}
|
||||
|
||||
NodeValue GetValue(const QString& input) const
|
||||
ShaderValue GetValue(const QString& input) const
|
||||
{
|
||||
return value_map_.value(input);
|
||||
}
|
||||
|
||||
void InsertValue(NodeInput* input, NodeValueDatabase& value)
|
||||
{
|
||||
ShaderValue shader_val;
|
||||
|
||||
shader_val.type = input->data_type();
|
||||
shader_val.array = input->IsArray();
|
||||
|
||||
if (input->IsArray()) {
|
||||
NodeInputArray* array = static_cast<NodeInputArray*>(input);
|
||||
QVector<NodeValue> values(array->GetSize());
|
||||
QVector<QVariant> values(array->GetSize());
|
||||
|
||||
for (int j=0;j<array->GetSize();j++) {
|
||||
NodeInput* subparam = array->At(j);
|
||||
|
||||
values[j] = value[subparam].TakeWithMeta(subparam->data_type());
|
||||
values[j] = value[subparam].Take(subparam->data_type());
|
||||
}
|
||||
|
||||
InsertValue(input->id(), NodeValue(NodeParam::kVec2, QVariant::fromValue(values), input->parentNode()));
|
||||
shader_val.data = QVariant::fromValue(values);
|
||||
} else {
|
||||
InsertValue(input->id(), value[input].TakeWithMeta(input->data_type()));
|
||||
NodeValue node_val = value[input].TakeWithMeta(input->data_type());
|
||||
shader_val.data = node_val.data();
|
||||
shader_val.tag = node_val.tag();
|
||||
}
|
||||
|
||||
InsertValue(input->id(), shader_val);
|
||||
}
|
||||
|
||||
void InsertValue(const QString& input, const NodeValue& value)
|
||||
void InsertValue(const QString& input, const ShaderValue& value)
|
||||
{
|
||||
value_map_.insert(input, value);
|
||||
}
|
||||
|
||||
void InsertValue(NodeInput* input, const NodeValue& value)
|
||||
void InsertValue(NodeInput* input, const ShaderValue& value)
|
||||
{
|
||||
value_map_.insert(input->id(), value);
|
||||
}
|
||||
|
||||
void InsertValue(NodeInput* input, const NodeValue& value)
|
||||
{
|
||||
ShaderValue s(value.data(), value.type());
|
||||
s.tag = value.tag();
|
||||
value_map_.insert(input->id(), s);
|
||||
}
|
||||
|
||||
const NodeValueMap &GetValues() const
|
||||
{
|
||||
return value_map_;
|
||||
@@ -127,15 +144,20 @@ public:
|
||||
|
||||
const QString& GetShaderID() const
|
||||
{
|
||||
return id_;
|
||||
return shader_id_;
|
||||
}
|
||||
|
||||
void SetShaderID(const QString& id)
|
||||
{
|
||||
id_ = id;
|
||||
shader_id_ = id;
|
||||
}
|
||||
|
||||
void SetIterations(int iterations, NodeInput* iterative_input)
|
||||
{
|
||||
SetIterations(iterations, iterative_input->id());
|
||||
}
|
||||
|
||||
void SetIterations(int iterations, const QString& iterative_input)
|
||||
{
|
||||
iterations_ = iterations;
|
||||
iterative_input_ = iterative_input;
|
||||
@@ -146,7 +168,7 @@ public:
|
||||
return iterations_;
|
||||
}
|
||||
|
||||
NodeInput* GetIterativeInput() const
|
||||
const QString& GetIterativeInput() const
|
||||
{
|
||||
return iterative_input_;
|
||||
}
|
||||
@@ -162,11 +184,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
QString id_;
|
||||
QString shader_id_;
|
||||
|
||||
int iterations_;
|
||||
|
||||
NodeInput* iterative_input_;
|
||||
QString iterative_input_;
|
||||
|
||||
bool bilinear_;
|
||||
|
||||
@@ -178,6 +200,13 @@ public:
|
||||
frag_code_(frag_code),
|
||||
vert_code_(vert_code)
|
||||
{
|
||||
if (frag_code_.isEmpty()) {
|
||||
frag_code_ = FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.frag"));
|
||||
}
|
||||
|
||||
if (vert_code_.isEmpty()) {
|
||||
vert_code_ = FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.vert"));
|
||||
}
|
||||
}
|
||||
|
||||
const QString& frag_code() const
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/***
|
||||
|
||||
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 SHADERVALUE_H
|
||||
#define SHADERVALUE_H
|
||||
|
||||
#include "node/param.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
struct ShaderValue
|
||||
{
|
||||
ShaderValue()
|
||||
{
|
||||
type = NodeParam::kNone;
|
||||
array = false;
|
||||
}
|
||||
|
||||
ShaderValue(QVariant data_in, NodeParam::DataType type_in, bool array_in = false)
|
||||
{
|
||||
data = data_in;
|
||||
type = type_in;
|
||||
array = array_in;
|
||||
}
|
||||
|
||||
NodeParam::DataType type;
|
||||
QVariant data;
|
||||
bool array;
|
||||
|
||||
QString tag;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // SHADERVALUE_H
|
||||
@@ -15,7 +15,6 @@ in vec2 ove_texcoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec2 using_texcoord = ove_texcoord;
|
||||
vec4 color = texture(ove_maintex, ove_texcoord);
|
||||
fragColor = color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,6 +248,13 @@ void ManagedDisplayWidget::doneCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::update()
|
||||
{
|
||||
if (RenderManager::instance()->backend() == RenderManager::kOpenGL) {
|
||||
static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_)->update();
|
||||
}
|
||||
}
|
||||
|
||||
Menu* ManagedDisplayWidget::GetDisplayMenu(QMenu* parent, bool auto_connect)
|
||||
{
|
||||
QStringList displays = color_manager()->ListAvailableDisplays();
|
||||
|
||||
@@ -114,6 +114,11 @@ public:
|
||||
*/
|
||||
Menu* GetLookMenu(QMenu* parent, bool auto_connect = true);
|
||||
|
||||
/**
|
||||
* @brief Passes update signal through to inner widget
|
||||
*/
|
||||
void update();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Replaces the color transform with a new one
|
||||
|
||||
@@ -43,8 +43,8 @@ void HistogramScope::OnInit()
|
||||
{
|
||||
ScopeBase::OnInit();
|
||||
|
||||
ShaderCode secondary_code(Node::ReadFileAsString(":/shaders/rgbhistogram_secondary.frag"),
|
||||
Node::ReadFileAsString(":/shaders/rgbhistogram.vert"));
|
||||
ShaderCode secondary_code(FileFunctions::ReadFileAsString(":/shaders/rgbhistogram_secondary.frag"),
|
||||
FileFunctions::ReadFileAsString(":/shaders/rgbhistogram.vert"));
|
||||
pipeline_secondary_ = renderer()->CreateNativeShader(secondary_code);
|
||||
}
|
||||
|
||||
@@ -58,8 +58,8 @@ void HistogramScope::OnDestroy()
|
||||
|
||||
ShaderCode HistogramScope::GenerateShaderCode()
|
||||
{
|
||||
return ShaderCode(Node::ReadFileAsString(":/shaders/rgbhistogram.frag"),
|
||||
Node::ReadFileAsString(":/shaders/default.vert"));
|
||||
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/rgbhistogram.frag"),
|
||||
FileFunctions::ReadFileAsString(":/shaders/default.vert"));
|
||||
}
|
||||
|
||||
void HistogramScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline)
|
||||
@@ -71,11 +71,11 @@ void HistogramScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeli
|
||||
float histogram_base = 2.5f;
|
||||
float histogram_power = 1.0f / histogram_base;
|
||||
|
||||
Renderer::ShaderUniformMap value_map;
|
||||
ShaderJob shader_job;
|
||||
|
||||
value_map.insert(QStringLiteral("viewport"), {QVector2D(width(), height()), NodeParam::kVec2});
|
||||
value_map.insert(QStringLiteral("histogram_scale"), {histogram_scale, NodeParam::kFloat});
|
||||
value_map.insert(QStringLiteral("histogram_power"), {histogram_power, NodeParam::kFloat});
|
||||
shader_job.InsertValue(QStringLiteral("viewport"), ShaderValue(QVector2D(width(), height()), NodeParam::kVec2));
|
||||
shader_job.InsertValue(QStringLiteral("histogram_scale"), ShaderValue(histogram_scale, NodeParam::kFloat));
|
||||
shader_job.InsertValue(QStringLiteral("histogram_power"), ShaderValue(histogram_power, NodeParam::kFloat));
|
||||
|
||||
if (!texture_row_sums_
|
||||
|| texture_row_sums_->width() != this->width()
|
||||
@@ -83,9 +83,13 @@ void HistogramScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeli
|
||||
texture_row_sums_ = renderer()->CreateTexture(VideoParams(width(), height(), managed_tex->format()));
|
||||
}
|
||||
|
||||
renderer()->Blit(managed_tex.get(), pipeline, value_map, texture_row_sums_.get());
|
||||
// Draw managed texture to a sums texture
|
||||
shader_job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture));
|
||||
renderer()->BlitToTexture(pipeline, shader_job, texture_row_sums_.get());
|
||||
|
||||
renderer()->Blit(texture_row_sums_.get(), pipeline_secondary_, value_map);
|
||||
// Draw sums into a histogram
|
||||
shader_job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(texture_row_sums_), NodeParam::kTexture));
|
||||
renderer()->Blit(pipeline_secondary_, shader_job, texture_row_sums_->params());
|
||||
|
||||
// Draw line overlays
|
||||
QPainter p(this);
|
||||
|
||||
@@ -50,7 +50,11 @@ void ScopeBase::showEvent(QShowEvent* e)
|
||||
|
||||
void ScopeBase::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline)
|
||||
{
|
||||
renderer()->Blit(managed_tex.get(), pipeline, Renderer::ShaderUniformMap());
|
||||
ShaderJob job;
|
||||
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture));
|
||||
|
||||
renderer()->Blit(pipeline, job, VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F));
|
||||
}
|
||||
|
||||
void ScopeBase::UploadTextureFromBuffer()
|
||||
@@ -98,9 +102,8 @@ void ScopeBase::OnPaint()
|
||||
|
||||
if (buffer_) {
|
||||
// Convert reference frame to display space
|
||||
renderer()->BlitColorManaged(color_service(), texture_.get(), managed_tex_.get());
|
||||
renderer()->BlitColorManaged(color_service(), texture_, managed_tex_.get());
|
||||
|
||||
renderer()->SetViewport(width(), height());
|
||||
DrawScope(managed_tex_, pipeline_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ WaveformScope::~WaveformScope()
|
||||
|
||||
ShaderCode WaveformScope::GenerateShaderCode()
|
||||
{
|
||||
return ShaderCode(Node::ReadFileAsString(":/shaders/rgbwaveform.frag"),
|
||||
Node::ReadFileAsString(":/shaders/rgbwaveform.vert"));
|
||||
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/rgbwaveform.frag"),
|
||||
FileFunctions::ReadFileAsString(":/shaders/rgbwaveform.vert"));
|
||||
}
|
||||
|
||||
void WaveformScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline)
|
||||
@@ -53,23 +53,28 @@ void WaveformScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipelin
|
||||
float waveform_scale = 0.80f;
|
||||
|
||||
// Draw waveform through shader
|
||||
Renderer::ShaderUniformMap value_map;
|
||||
ShaderJob job;
|
||||
|
||||
// Set viewport size
|
||||
value_map.insert(QStringLiteral("viewport"),
|
||||
{QVector2D(width(), height()), NodeParam::kVec2});
|
||||
job.InsertValue(QStringLiteral("viewport"),
|
||||
ShaderValue(QVector2D(width(), height()), NodeParam::kVec2));
|
||||
|
||||
// Set luma coefficients
|
||||
float luma_coeffs[3] = {0.0f, 0.0f, 0.0f};
|
||||
color_manager()->GetDefaultLumaCoefs(luma_coeffs);
|
||||
value_map.insert(QStringLiteral("luma_coeffs"),
|
||||
{QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]), NodeParam::kVec3});
|
||||
job.InsertValue(QStringLiteral("luma_coeffs"),
|
||||
ShaderValue(QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]), NodeParam::kVec3));
|
||||
|
||||
|
||||
// Scale of the waveform relative to the viewport surface.
|
||||
value_map.insert(QStringLiteral("waveform_scale"), {waveform_scale, NodeParam::kFloat});
|
||||
job.InsertValue(QStringLiteral("waveform_scale"),
|
||||
ShaderValue(waveform_scale, NodeParam::kFloat));
|
||||
|
||||
renderer()->Blit(managed_tex.get(), pipeline, value_map);
|
||||
// Insert source texture
|
||||
job.InsertValue(QStringLiteral("ove_maintex"),
|
||||
ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture));
|
||||
|
||||
renderer()->Blit(pipeline, job, VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F));
|
||||
|
||||
float waveform_dim_x = ceil((width() - 1.0) * waveform_scale);
|
||||
float waveform_dim_y = ceil((height() - 1.0) * waveform_scale);
|
||||
|
||||
@@ -202,6 +202,8 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
|
||||
using_manager = nullptr;
|
||||
}
|
||||
|
||||
auto_cacher_.SetColorManager(using_manager);
|
||||
|
||||
display_widget_->ConnectColorManager(using_manager);
|
||||
foreach (ViewerWindow* window, windows_) {
|
||||
window->display_widget()->ConnectColorManager(using_manager);
|
||||
@@ -244,6 +246,7 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
|
||||
foreach (ViewerWindow* window, windows_) {
|
||||
window->display_widget()->DisconnectColorManager();
|
||||
}
|
||||
auto_cacher_.SetColorManager(nullptr);
|
||||
|
||||
waveform_view_->SetViewer(nullptr);
|
||||
waveform_view_->ConnectTimelinePoints(nullptr);
|
||||
|
||||
@@ -297,9 +297,8 @@ void ViewerDisplayWidget::OnPaint()
|
||||
//color_service()->pipeline()->setUniformValue("ove_deinterlace", deinterlace_);
|
||||
}
|
||||
|
||||
// Bind retrieved texture
|
||||
renderer()->SetViewport(width(), height());
|
||||
renderer()->BlitColorManaged(color_service(), texture_.get());
|
||||
// Draw texture through color transform
|
||||
renderer()->BlitColorManaged(color_service(), texture_, VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F));
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user