uhh yeah this might be fubar
This commit is contained in:
@@ -49,7 +49,6 @@
|
|||||||
#include "panel/panelmanager.h"
|
#include "panel/panelmanager.h"
|
||||||
#include "panel/project/project.h"
|
#include "panel/project/project.h"
|
||||||
#include "panel/viewer/viewer.h"
|
#include "panel/viewer/viewer.h"
|
||||||
#include "render/backend/opengl/opengltexturecache.h"
|
|
||||||
#include "render/colormanager.h"
|
#include "render/colormanager.h"
|
||||||
#include "render/diskmanager.h"
|
#include "render/diskmanager.h"
|
||||||
#include "render/pixelformat.h"
|
#include "render/pixelformat.h"
|
||||||
@@ -96,8 +95,6 @@ Core *Core::instance()
|
|||||||
void Core::DeclareTypesForQt()
|
void Core::DeclareTypesForQt()
|
||||||
{
|
{
|
||||||
qRegisterMetaType<rational>();
|
qRegisterMetaType<rational>();
|
||||||
qRegisterMetaType<OpenGLTexturePtr>();
|
|
||||||
qRegisterMetaType<OpenGLTextureCache::ReferencePtr>();
|
|
||||||
qRegisterMetaType<NodeValue>();
|
qRegisterMetaType<NodeValue>();
|
||||||
qRegisterMetaType<NodeValueTable>();
|
qRegisterMetaType<NodeValueTable>();
|
||||||
qRegisterMetaType<NodeValueDatabase>();
|
qRegisterMetaType<NodeValueDatabase>();
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ void ViewerOutput::ShiftAudioCache(const rational &from, const rational &to)
|
|||||||
audio_playback_cache_.Shift(from, to);
|
audio_playback_cache_.Shift(from, to);
|
||||||
|
|
||||||
foreach (TrackOutput* track, track_lists_.at(Timeline::kTrackTypeAudio)->GetTracks()) {
|
foreach (TrackOutput* track, track_lists_.at(Timeline::kTrackTypeAudio)->GetTracks()) {
|
||||||
QMutexLocker locker(track->waveform_lock());
|
|
||||||
track->waveform().Shift(from, to);
|
track->waveform().Shift(from, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ add_subdirectory(opengl)
|
|||||||
|
|
||||||
set(OLIVE_SOURCES
|
set(OLIVE_SOURCES
|
||||||
${OLIVE_SOURCES}
|
${OLIVE_SOURCES}
|
||||||
render/backend/rendercontext.cpp
|
render/backend/renderer.cpp
|
||||||
render/backend/rendercontext.h
|
render/backend/renderer.h
|
||||||
render/backend/rendercontextthreadwrapper.cpp
|
render/backend/rendererthreadwrapper.cpp
|
||||||
render/backend/rendercontextthreadwrapper.h
|
render/backend/rendererthreadwrapper.h
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
set(OLIVE_SOURCES
|
set(OLIVE_SOURCES
|
||||||
${OLIVE_SOURCES}
|
${OLIVE_SOURCES}
|
||||||
render/backend/opengl/openglcontext.cpp
|
render/backend/opengl/openglrenderer.cpp
|
||||||
render/backend/opengl/openglcontext.h
|
render/backend/opengl/openglrenderer.h
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,195 +0,0 @@
|
|||||||
/***
|
|
||||||
|
|
||||||
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 "openglcontext.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
|
||||||
|
|
||||||
OpenGLContext::OpenGLContext(QObject* parent) :
|
|
||||||
RenderContext(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenGLContext::~OpenGLContext()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGLContext::Init()
|
|
||||||
{
|
|
||||||
surface_.create();
|
|
||||||
|
|
||||||
context_ = new QOpenGLContext();
|
|
||||||
if (!context_->create()) {
|
|
||||||
qCritical() << "Failed to create OpenGL context";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
context_->moveToThread(this->thread());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLContext::PostInit()
|
|
||||||
{
|
|
||||||
// Make context current on that surface
|
|
||||||
if (!context_->makeCurrent(&surface_)) {
|
|
||||||
qCritical() << "Failed to makeCurrent() on offscreen surface in thread" << thread();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store OpenGL functions instance
|
|
||||||
functions_ = context_->functions();
|
|
||||||
functions_->glBlendFunc(GL_ONE, GL_ZERO);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLContext::Destroy()
|
|
||||||
{
|
|
||||||
delete context_;
|
|
||||||
surface_.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant OpenGLContext::CreateTexture(const VideoParams &p, void *data, int linesize)
|
|
||||||
{
|
|
||||||
GLuint texture;
|
|
||||||
functions_->glGenTextures(1, &texture);
|
|
||||||
texture_params_.insert(texture, p);
|
|
||||||
|
|
||||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
|
||||||
|
|
||||||
functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(p.format()),
|
|
||||||
p.width(), p.height(), 0, GetPixelFormat(p.format()),
|
|
||||||
GetPixelType(p.format()), data);
|
|
||||||
|
|
||||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLContext::DestroyTexture(QVariant texture)
|
|
||||||
{
|
|
||||||
GLuint t = texture.value<GLuint>();
|
|
||||||
functions_->glDeleteTextures(1, &t);
|
|
||||||
texture_params_.remove(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLContext::UploadToTexture(QVariant texture, void *data, int linesize)
|
|
||||||
{
|
|
||||||
GLuint t = texture.value<GLuint>();
|
|
||||||
const VideoParams& p = texture_params_.value(t);
|
|
||||||
|
|
||||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
|
||||||
|
|
||||||
functions_->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
|
||||||
p.effective_width(), p.effective_height(),
|
|
||||||
GetPixelFormat(p.format()), GetPixelType(p.format()),
|
|
||||||
data);
|
|
||||||
|
|
||||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLContext::DownloadFromTexture(QVariant texture, void *data, int linesize)
|
|
||||||
{
|
|
||||||
GLuint t = texture.value<GLuint>();
|
|
||||||
const VideoParams& p = texture_params_.value(t);
|
|
||||||
|
|
||||||
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, linesize);
|
|
||||||
|
|
||||||
functions_->glReadPixels(0,
|
|
||||||
0,
|
|
||||||
p.width(),
|
|
||||||
p.height(),
|
|
||||||
GetPixelFormat(p.format()),
|
|
||||||
GetPixelType(p.format()),
|
|
||||||
data);
|
|
||||||
|
|
||||||
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoParams OpenGLContext::GetParamsFromTexture(QVariant texture)
|
|
||||||
{
|
|
||||||
GLuint t = texture.value<GLuint>();
|
|
||||||
|
|
||||||
return texture_params_.value(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint OpenGLContext::GetInternalFormat(PixelFormat::Format format)
|
|
||||||
{
|
|
||||||
switch (format) {
|
|
||||||
case PixelFormat::PIX_FMT_RGB8:
|
|
||||||
return GL_RGB8;
|
|
||||||
case PixelFormat::PIX_FMT_RGBA8:
|
|
||||||
return GL_RGBA8;
|
|
||||||
case PixelFormat::PIX_FMT_RGB16U:
|
|
||||||
return GL_RGB16;
|
|
||||||
case PixelFormat::PIX_FMT_RGBA16U:
|
|
||||||
return GL_RGBA16;
|
|
||||||
case PixelFormat::PIX_FMT_RGB16F:
|
|
||||||
return GL_RGB16F;
|
|
||||||
case PixelFormat::PIX_FMT_RGBA16F:
|
|
||||||
return GL_RGBA16F;
|
|
||||||
case PixelFormat::PIX_FMT_RGB32F:
|
|
||||||
return GL_RGB32F;
|
|
||||||
case PixelFormat::PIX_FMT_RGBA32F:
|
|
||||||
return GL_RGBA32F;
|
|
||||||
|
|
||||||
case PixelFormat::PIX_FMT_INVALID:
|
|
||||||
case PixelFormat::PIX_FMT_COUNT:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GL_INVALID_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLenum OpenGLContext::GetPixelFormat(PixelFormat::Format format)
|
|
||||||
{
|
|
||||||
if (PixelFormat::FormatHasAlphaChannel(format)) {
|
|
||||||
return GL_RGBA;
|
|
||||||
} else {
|
|
||||||
return GL_RGB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GLenum OpenGLContext::GetPixelType(PixelFormat::Format format)
|
|
||||||
{
|
|
||||||
switch (format) {
|
|
||||||
case PixelFormat::PIX_FMT_RGB8:
|
|
||||||
case PixelFormat::PIX_FMT_RGBA8:
|
|
||||||
return GL_UNSIGNED_BYTE;
|
|
||||||
case PixelFormat::PIX_FMT_RGB16U:
|
|
||||||
case PixelFormat::PIX_FMT_RGBA16U:
|
|
||||||
return GL_UNSIGNED_SHORT;
|
|
||||||
case PixelFormat::PIX_FMT_RGB16F:
|
|
||||||
case PixelFormat::PIX_FMT_RGBA16F:
|
|
||||||
return GL_HALF_FLOAT;
|
|
||||||
case PixelFormat::PIX_FMT_RGB32F:
|
|
||||||
case PixelFormat::PIX_FMT_RGBA32F:
|
|
||||||
return GL_FLOAT;
|
|
||||||
|
|
||||||
case PixelFormat::PIX_FMT_INVALID:
|
|
||||||
case PixelFormat::PIX_FMT_COUNT:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GL_INVALID_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
|
||||||
@@ -0,0 +1,504 @@
|
|||||||
|
/***
|
||||||
|
|
||||||
|
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 "openglrenderer.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
|
OpenGLRenderer::OpenGLRenderer(QObject* parent) :
|
||||||
|
Renderer(parent),
|
||||||
|
context_(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLRenderer::~OpenGLRenderer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderer::Init(QOpenGLContext *existing_ctx)
|
||||||
|
{
|
||||||
|
if (context_) {
|
||||||
|
qCritical() << "Can't initialize already initialized OpenGLRenderer";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context_ = existing_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenGLRenderer::Init()
|
||||||
|
{
|
||||||
|
if (context_) {
|
||||||
|
qCritical() << "Can't initialize already initialized OpenGLRenderer";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface_.create();
|
||||||
|
|
||||||
|
context_ = new QOpenGLContext(this);
|
||||||
|
if (!context_->create()) {
|
||||||
|
qCritical() << "Failed to create OpenGL context";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
context_->moveToThread(this->thread());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderer::PostInit()
|
||||||
|
{
|
||||||
|
// Make context current on that surface
|
||||||
|
if (!context_->makeCurrent(&surface_)) {
|
||||||
|
qCritical() << "Failed to makeCurrent() on offscreen surface in thread" << thread();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store OpenGL functions instance
|
||||||
|
functions_ = context_->functions();
|
||||||
|
functions_->glBlendFunc(GL_ONE, GL_ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderer::Destroy()
|
||||||
|
{
|
||||||
|
if (context_->parent() == this) {
|
||||||
|
delete context_;
|
||||||
|
}
|
||||||
|
context_ = nullptr;
|
||||||
|
|
||||||
|
qDeleteAll(shader_cache_);
|
||||||
|
shader_cache_.clear();
|
||||||
|
|
||||||
|
if (surface_.isValid()) {
|
||||||
|
surface_.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant OpenGLRenderer::CreateNativeTexture(const VideoParams &p, void *data, int linesize)
|
||||||
|
{
|
||||||
|
GLuint texture;
|
||||||
|
functions_->glGenTextures(1, &texture);
|
||||||
|
|
||||||
|
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
||||||
|
|
||||||
|
functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(p.format()),
|
||||||
|
p.width(), p.height(), 0, GetPixelFormat(p.format()),
|
||||||
|
GetPixelType(p.format()), data);
|
||||||
|
|
||||||
|
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderer::DestroyNativeTexture(QVariant texture)
|
||||||
|
{
|
||||||
|
GLuint t = texture.value<GLuint>();
|
||||||
|
functions_->glDeleteTextures(1, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderer::UploadToTexture(Texture *texture, void *data, int linesize)
|
||||||
|
{
|
||||||
|
GLuint t = texture->id().value<GLuint>();
|
||||||
|
const VideoParams& p = texture->params();
|
||||||
|
|
||||||
|
// Store currently bound texture so it can be restored later
|
||||||
|
GLint current_tex;
|
||||||
|
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex);
|
||||||
|
|
||||||
|
functions_->glBindTexture(GL_TEXTURE_2D, t);
|
||||||
|
|
||||||
|
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
||||||
|
|
||||||
|
functions_->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
||||||
|
p.effective_width(), p.effective_height(),
|
||||||
|
GetPixelFormat(p.format()), GetPixelType(p.format()),
|
||||||
|
data);
|
||||||
|
|
||||||
|
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
|
||||||
|
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int linesize)
|
||||||
|
{
|
||||||
|
GLuint t = texture->id().value<GLuint>();
|
||||||
|
const VideoParams& p = texture->params();
|
||||||
|
|
||||||
|
GLint current_tex;
|
||||||
|
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex);
|
||||||
|
|
||||||
|
functions_->glBindTexture(GL_TEXTURE_2D, t);
|
||||||
|
|
||||||
|
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, linesize);
|
||||||
|
|
||||||
|
functions_->glReadPixels(0,
|
||||||
|
0,
|
||||||
|
p.width(),
|
||||||
|
p.height(),
|
||||||
|
GetPixelFormat(p.format()),
|
||||||
|
GetPixelType(p.format()),
|
||||||
|
data);
|
||||||
|
|
||||||
|
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||||
|
|
||||||
|
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job, const VideoParams ¶ms)
|
||||||
|
{
|
||||||
|
// 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 = OpenGLShader::CodeDefaultFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vert_code.isEmpty()) {
|
||||||
|
vert_code = OpenGLShader::CodeDefaultVertex();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shader->bind();
|
||||||
|
|
||||||
|
NodeValueMap::const_iterator it;
|
||||||
|
for (it=job.GetValues().constBegin(); it!=job.GetValues().constEnd(); it++) {
|
||||||
|
// See if the shader has takes this parameter as an input
|
||||||
|
int variable_location = shader->uniformLocation(it.key());
|
||||||
|
|
||||||
|
if (variable_location == -1) {
|
||||||
|
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();
|
||||||
|
|
||||||
|
NodeParam::DataType data_type = (it.value().type() != NodeParam::kNone)
|
||||||
|
? it.value().type()
|
||||||
|
: corresponding_input->data_type();
|
||||||
|
|
||||||
|
switch (data_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());
|
||||||
|
break;
|
||||||
|
case NodeInput::kFloat:
|
||||||
|
// kFloat technically specifies a double but as above, OpenGL doesn't support those.
|
||||||
|
shader->setUniformValue(variable_location, value.toFloat());
|
||||||
|
break;
|
||||||
|
case NodeInput::kVec2:
|
||||||
|
if (corresponding_input && corresponding_input->IsArray()) {
|
||||||
|
QVector<NodeValue> nv = value.value< QVector<NodeValue> >();
|
||||||
|
QVector<QVector2D> a(nv.size());
|
||||||
|
|
||||||
|
for (int j=0;j<a.size();j++) {
|
||||||
|
a[j] = nv.at(j).data().value<QVector2D>();
|
||||||
|
}
|
||||||
|
|
||||||
|
shader->setUniformValueArray(variable_location, a.constData(), a.size());
|
||||||
|
|
||||||
|
int count_location = shader->uniformLocation(QStringLiteral("%1_count").arg(it.key()));
|
||||||
|
if (count_location > -1) {
|
||||||
|
shader->setUniformValue(count_location, a.size());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shader->setUniformValue(variable_location, value.value<QVector2D>());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NodeInput::kVec3:
|
||||||
|
shader->setUniformValue(variable_location, value.value<QVector3D>());
|
||||||
|
break;
|
||||||
|
case NodeInput::kVec4:
|
||||||
|
shader->setUniformValue(variable_location, value.value<QVector4D>());
|
||||||
|
break;
|
||||||
|
case NodeInput::kMatrix:
|
||||||
|
shader->setUniformValue(variable_location, value.value<QMatrix4x4>());
|
||||||
|
break;
|
||||||
|
case NodeInput::kCombo:
|
||||||
|
shader->setUniformValue(variable_location, value.value<int>());
|
||||||
|
break;
|
||||||
|
case NodeInput::kColor:
|
||||||
|
{
|
||||||
|
Color color = value.value<Color>();
|
||||||
|
|
||||||
|
shader->setUniformValue(variable_location, color.red(), color.green(), color.blue(), color.alpha());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NodeInput::kBoolean:
|
||||||
|
shader->setUniformValue(variable_location, value.toBool());
|
||||||
|
break;
|
||||||
|
case NodeInput::kBuffer:
|
||||||
|
case NodeInput::kTexture:
|
||||||
|
{
|
||||||
|
TexturePtr texture = value.value<TexturePtr>();
|
||||||
|
|
||||||
|
if (texture) {
|
||||||
|
if (PixelFormat::FormatHasAlphaChannel(texture->format())) {
|
||||||
|
input_textures_have_alpha = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()) {
|
||||||
|
iterative_input = textures_to_bind.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint tex_id = texture ? texture->id().value<GLuint>() : 0;
|
||||||
|
textures_to_bind.append(tex_id);
|
||||||
|
|
||||||
|
// Set enable flag if shader wants it
|
||||||
|
int enable_param_location = shader->uniformLocation(QStringLiteral("%1_enabled").arg(it.key()));
|
||||||
|
if (enable_param_location > -1) {
|
||||||
|
shader->setUniformValue(enable_param_location,
|
||||||
|
tex_id > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tex_id > 0) {
|
||||||
|
// Set texture resolution if shader wants it
|
||||||
|
int res_param_location = shader->uniformLocation(QStringLiteral("%1_resolution").arg(it.key()));
|
||||||
|
if (res_param_location > -1) {
|
||||||
|
int adjusted_width = texture->width() * texture->divider();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
adjusted_width = qRound(static_cast<double>(adjusted_width) * relative_pixel_aspect);
|
||||||
|
}
|
||||||
|
|
||||||
|
shader->setUniformValue(res_param_location,
|
||||||
|
adjusted_width,
|
||||||
|
static_cast<GLfloat>(texture->height() * texture->divider()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NodeInput::kSamples:
|
||||||
|
case NodeInput::kText:
|
||||||
|
case NodeInput::kRational:
|
||||||
|
case NodeInput::kFont:
|
||||||
|
case NodeInput::kFile:
|
||||||
|
case NodeInput::kDecimal:
|
||||||
|
case NodeInput::kNumber:
|
||||||
|
case NodeInput::kString:
|
||||||
|
case NodeInput::kVector:
|
||||||
|
case NodeInput::kShaderJob:
|
||||||
|
case NodeInput::kSampleJob:
|
||||||
|
case NodeInput::kGenerateJob:
|
||||||
|
case NodeInput::kFootage:
|
||||||
|
case NodeInput::kNone:
|
||||||
|
case NodeInput::kAny:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide some standard args
|
||||||
|
shader->setUniformValue("ove_resolution",
|
||||||
|
static_cast<GLfloat>(params.width()),
|
||||||
|
static_cast<GLfloat>(params.height()));
|
||||||
|
|
||||||
|
shader->release();
|
||||||
|
|
||||||
|
// Create the output textures
|
||||||
|
PixelFormat::Format output_format = (input_textures_have_alpha || job.GetAlphaChannelRequired())
|
||||||
|
? PixelFormat::GetFormatWithAlphaChannel(params.format())
|
||||||
|
: PixelFormat::GetFormatWithoutAlphaChannel(params.format());
|
||||||
|
VideoParams output_params(params.width(),
|
||||||
|
params.height(),
|
||||||
|
params.time_base(),
|
||||||
|
output_format,
|
||||||
|
params.pixel_aspect_ratio(),
|
||||||
|
params.interlacing(),
|
||||||
|
params.divider());
|
||||||
|
|
||||||
|
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(output_params);
|
||||||
|
|
||||||
|
// If this node requires multiple iterations, get a texture for it too
|
||||||
|
if (real_iteration_count > 1) {
|
||||||
|
dst_refs[1] = CreateTexture(output_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());
|
||||||
|
|
||||||
|
// Bind all textures
|
||||||
|
for (int i=0; i<textures_to_bind.size(); i++) {
|
||||||
|
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
functions_->glBindTexture(GL_TEXTURE_2D, textures_to_bind.at(i));
|
||||||
|
OpenGLRenderFunctions::PrepareToDraw(functions_);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int iteration=0; iteration<real_iteration_count; iteration++) {
|
||||||
|
// Set iteration number
|
||||||
|
shader->bind();
|
||||||
|
shader->setUniformValue("ove_iteration", iteration);
|
||||||
|
shader->release();
|
||||||
|
|
||||||
|
// Replace iterative input
|
||||||
|
if (iteration == 0) {
|
||||||
|
output_tex = dst_refs[0];
|
||||||
|
} else {
|
||||||
|
input_tex = dst_refs[(iteration+1)%2];
|
||||||
|
output_tex = dst_refs[iteration%2];
|
||||||
|
|
||||||
|
functions_->glActiveTexture(GL_TEXTURE0 + iterative_input);
|
||||||
|
functions_->glBindTexture(GL_TEXTURE_2D, input_tex->texture()->texture());
|
||||||
|
OpenGLRenderFunctions::PrepareToDraw(functions_);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_.Attach(output_tex, true);
|
||||||
|
buffer_.Bind();
|
||||||
|
|
||||||
|
// Blit this texture through this shader
|
||||||
|
OpenGLRenderFunctions::Blit(shader);
|
||||||
|
|
||||||
|
buffer_.Release();
|
||||||
|
buffer_.Detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release any textures we bound before
|
||||||
|
for (int i=textures_to_bind.size()-1; i>=0; i--) {
|
||||||
|
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
functions_->glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output_tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*VideoParams OpenGLRenderer::GetParamsFromTexture(QVariant texture)
|
||||||
|
{
|
||||||
|
GLuint t = texture.value<GLuint>();
|
||||||
|
|
||||||
|
return texture_params_.value(t);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case PixelFormat::PIX_FMT_RGB8:
|
||||||
|
return GL_RGB8;
|
||||||
|
case PixelFormat::PIX_FMT_RGBA8:
|
||||||
|
return GL_RGBA8;
|
||||||
|
case PixelFormat::PIX_FMT_RGB16U:
|
||||||
|
return GL_RGB16;
|
||||||
|
case PixelFormat::PIX_FMT_RGBA16U:
|
||||||
|
return GL_RGBA16;
|
||||||
|
case PixelFormat::PIX_FMT_RGB16F:
|
||||||
|
return GL_RGB16F;
|
||||||
|
case PixelFormat::PIX_FMT_RGBA16F:
|
||||||
|
return GL_RGBA16F;
|
||||||
|
case PixelFormat::PIX_FMT_RGB32F:
|
||||||
|
return GL_RGB32F;
|
||||||
|
case PixelFormat::PIX_FMT_RGBA32F:
|
||||||
|
return GL_RGBA32F;
|
||||||
|
|
||||||
|
case PixelFormat::PIX_FMT_INVALID:
|
||||||
|
case PixelFormat::PIX_FMT_COUNT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GL_INVALID_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLenum OpenGLRenderer::GetPixelFormat(PixelFormat::Format format)
|
||||||
|
{
|
||||||
|
if (PixelFormat::FormatHasAlphaChannel(format)) {
|
||||||
|
return GL_RGBA;
|
||||||
|
} else {
|
||||||
|
return GL_RGB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GLenum OpenGLRenderer::GetPixelType(PixelFormat::Format format)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case PixelFormat::PIX_FMT_RGB8:
|
||||||
|
case PixelFormat::PIX_FMT_RGBA8:
|
||||||
|
return GL_UNSIGNED_BYTE;
|
||||||
|
case PixelFormat::PIX_FMT_RGB16U:
|
||||||
|
case PixelFormat::PIX_FMT_RGBA16U:
|
||||||
|
return GL_UNSIGNED_SHORT;
|
||||||
|
case PixelFormat::PIX_FMT_RGB16F:
|
||||||
|
case PixelFormat::PIX_FMT_RGBA16F:
|
||||||
|
return GL_HALF_FLOAT;
|
||||||
|
case PixelFormat::PIX_FMT_RGB32F:
|
||||||
|
case PixelFormat::PIX_FMT_RGBA32F:
|
||||||
|
return GL_FLOAT;
|
||||||
|
|
||||||
|
case PixelFormat::PIX_FMT_INVALID:
|
||||||
|
case PixelFormat::PIX_FMT_COUNT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GL_INVALID_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_EXIT
|
||||||
+20
-10
@@ -23,19 +23,22 @@
|
|||||||
|
|
||||||
#include <QOffscreenSurface>
|
#include <QOffscreenSurface>
|
||||||
#include <QOpenGLFunctions>
|
#include <QOpenGLFunctions>
|
||||||
|
#include <QOpenGLShader>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
#include "render/backend/rendercontext.h"
|
#include "render/backend/renderer.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
class OpenGLContext : public RenderContext
|
class OpenGLRenderer : public Renderer
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
OpenGLContext(QObject* parent = nullptr);
|
OpenGLRenderer(QObject* parent = nullptr);
|
||||||
|
|
||||||
virtual ~OpenGLContext() override;
|
virtual ~OpenGLRenderer() override;
|
||||||
|
|
||||||
|
void Init(QOpenGLContext* existing_ctx);
|
||||||
|
|
||||||
virtual bool Init() override;
|
virtual bool Init() override;
|
||||||
|
|
||||||
@@ -44,15 +47,20 @@ public slots:
|
|||||||
|
|
||||||
virtual void Destroy() override;
|
virtual void Destroy() override;
|
||||||
|
|
||||||
virtual QVariant CreateTexture(const VideoParams& param, void* data, int linesize) override;
|
virtual QVariant CreateNativeTexture(const VideoParams& p, void* data = nullptr, int linesize = 0) override;
|
||||||
|
|
||||||
virtual void DestroyTexture(QVariant texture) override;
|
virtual void DestroyNativeTexture(QVariant texture) override;
|
||||||
|
|
||||||
virtual void UploadToTexture(QVariant texture, void* data, int linesize) override;
|
virtual void UploadToTexture(Texture* texture, void* data, int linesize) override;
|
||||||
|
|
||||||
virtual void DownloadFromTexture(QVariant texture, void* data, int linesize) override;
|
virtual void DownloadFromTexture(Texture* texture, void* data, int linesize) override;
|
||||||
|
|
||||||
virtual VideoParams GetParamsFromTexture(QVariant texture) override;
|
virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node,
|
||||||
|
const OLIVE_NAMESPACE::TimeRange &range,
|
||||||
|
const OLIVE_NAMESPACE::ShaderJob &job,
|
||||||
|
const OLIVE_NAMESPACE::VideoParams ¶ms) override;
|
||||||
|
|
||||||
|
virtual QVariant TransformColor(QVariant texture, ColorProcessorPtr processor) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static GLint GetInternalFormat(PixelFormat::Format format);
|
static GLint GetInternalFormat(PixelFormat::Format format);
|
||||||
@@ -67,10 +75,12 @@ private:
|
|||||||
|
|
||||||
QOffscreenSurface surface_;
|
QOffscreenSurface surface_;
|
||||||
|
|
||||||
QMap<GLuint, VideoParams> texture_params_;
|
QHash<QString, QOpenGLShaderProgram*> shader_cache_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::OpenGLRenderer::TexturePtr);
|
||||||
|
|
||||||
#endif // OPENGLCONTEXT_H
|
#endif // OPENGLCONTEXT_H
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
/***
|
||||||
|
|
||||||
|
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 "openglshader.h"
|
||||||
|
|
||||||
|
#include <QOpenGLExtraFunctions>
|
||||||
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
|
OpenGLShaderPtr OpenGLShader::Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<OpenGLShader>();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLShaderPtr OpenGLShader::CreateDefault(const QString &function_name, const QString &shader_code)
|
||||||
|
{
|
||||||
|
OpenGLShaderPtr program = Create();
|
||||||
|
|
||||||
|
// Add shaders to program
|
||||||
|
program->addShaderFromSourceCode(QOpenGLShader::Vertex, CodeDefaultVertex());
|
||||||
|
program->addShaderFromSourceCode(QOpenGLShader::Fragment, CodeDefaultFragment(function_name, shader_code));
|
||||||
|
program->link();
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copied from source code to OCIODisplay
|
||||||
|
const int OCIO_LUT3D_EDGE_SIZE = 64;
|
||||||
|
|
||||||
|
// copied from source code to OCIODisplay, expanded from 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE
|
||||||
|
const int OCIO_NUM_3D_ENTRIES = 3*OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE;
|
||||||
|
|
||||||
|
OpenGLShaderPtr OpenGLShader::CreateOCIO(QOpenGLContext* ctx,
|
||||||
|
GLuint& lut_texture,
|
||||||
|
OCIO::ConstProcessorRcPtr processor,
|
||||||
|
bool alpha_is_associated)
|
||||||
|
{
|
||||||
|
QOpenGLExtraFunctions* xf = ctx->extraFunctions();
|
||||||
|
|
||||||
|
// Set up shader description
|
||||||
|
OCIO::GpuShaderDesc shaderDesc;
|
||||||
|
const char* ocio_func_name = "OCIODisplay";
|
||||||
|
shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3);
|
||||||
|
shaderDesc.setFunctionName(ocio_func_name);
|
||||||
|
shaderDesc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE);
|
||||||
|
|
||||||
|
// Compute LUT
|
||||||
|
std::vector<float> ocio_lut_data(OCIO_NUM_3D_ENTRIES);
|
||||||
|
processor->getGpuLut3D(&ocio_lut_data[0], shaderDesc);
|
||||||
|
|
||||||
|
// Create LUT texture
|
||||||
|
xf->glGenTextures(1, &lut_texture);
|
||||||
|
|
||||||
|
// Bind LUT
|
||||||
|
xf->glActiveTexture(GL_TEXTURE1);
|
||||||
|
xf->glBindTexture(GL_TEXTURE_3D, lut_texture);
|
||||||
|
|
||||||
|
// Set texture parameters
|
||||||
|
xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
// Allocate storage for texture
|
||||||
|
xf->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F,
|
||||||
|
OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE,
|
||||||
|
0, GL_RGB, GL_FLOAT, &ocio_lut_data[0]);
|
||||||
|
|
||||||
|
// Create OCIO shader code
|
||||||
|
QString shader_text;
|
||||||
|
|
||||||
|
// Workaround since OCIO doesn't support the GLSL version we use
|
||||||
|
shader_text.append(QStringLiteral("#define texture2D texture\n"
|
||||||
|
"#define texture3D texture\n"));
|
||||||
|
|
||||||
|
// Append OCIO shader code
|
||||||
|
shader_text.append(processor->getGpuShaderText(shaderDesc));
|
||||||
|
|
||||||
|
QString shader_call;
|
||||||
|
|
||||||
|
// Enforce alpha association
|
||||||
|
if (alpha_is_associated) {
|
||||||
|
|
||||||
|
// If alpha is already associated, we'll need to disassociate and reassociate
|
||||||
|
shader_text.append("\n");
|
||||||
|
|
||||||
|
QString disassociate_func_name = "disassoc";
|
||||||
|
shader_text.append(CodeAlphaDisassociate(disassociate_func_name));
|
||||||
|
|
||||||
|
QString reassociate_func_name = "reassoc";
|
||||||
|
shader_text.append(CodeAlphaReassociate(reassociate_func_name));
|
||||||
|
|
||||||
|
// Make OCIO call pass through disassociate and reassociate function
|
||||||
|
shader_call = QStringLiteral("%3(%1(%2(col), ove_ociolut));").arg(ocio_func_name,
|
||||||
|
disassociate_func_name,
|
||||||
|
reassociate_func_name);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// If alpha is not already associated, we can just associate after OCIO
|
||||||
|
|
||||||
|
// Add associate function
|
||||||
|
QString associate_func_name = "assoc";
|
||||||
|
shader_text.append(CodeAlphaAssociate(associate_func_name));
|
||||||
|
|
||||||
|
// Make OCIO call pass through associate function
|
||||||
|
shader_call = QStringLiteral("%2(%1(col, ove_ociolut));").arg(ocio_func_name, associate_func_name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add process() function, which GetPipeline() will call if specified
|
||||||
|
QString process_function_name = "process";
|
||||||
|
shader_text.append(QStringLiteral("\n"
|
||||||
|
"uniform sampler3D ove_ociolut;\n"
|
||||||
|
"\n"
|
||||||
|
"vec4 %2(vec4 col) {\n"
|
||||||
|
" return %1\n"
|
||||||
|
"}\n").arg(shader_call, process_function_name));
|
||||||
|
|
||||||
|
|
||||||
|
// Get pipeline-based shader to inject OCIO shader into
|
||||||
|
OpenGLShaderPtr shader = OpenGLShader::CreateDefault(process_function_name, shader_text);
|
||||||
|
|
||||||
|
// Release LUT
|
||||||
|
xf->glBindTexture(GL_TEXTURE_3D, 0);
|
||||||
|
|
||||||
|
xf->glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenGLShader::CodeDefaultFragment(QString function_name, const QString &shader_code)
|
||||||
|
{
|
||||||
|
// Create shader header
|
||||||
|
QString frag_code = QStringLiteral("#version 150\n"
|
||||||
|
"\n"
|
||||||
|
"#ifdef GL_ES\n"
|
||||||
|
"precision highp int;\n"
|
||||||
|
"precision highp float;\n"
|
||||||
|
"#endif\n"
|
||||||
|
"\n"
|
||||||
|
"uniform sampler2D ove_maintex;\n"
|
||||||
|
"uniform vec2 ove_resolution;\n"
|
||||||
|
"uniform bool ove_deinterlace;\n"
|
||||||
|
"\n"
|
||||||
|
"in vec2 ove_texcoord;\n"
|
||||||
|
"\n"
|
||||||
|
"out vec4 fragColor;\n"
|
||||||
|
"\n");
|
||||||
|
|
||||||
|
// Check if additional code was passed to this function, add it here
|
||||||
|
if (!function_name.isEmpty() && !shader_code.isEmpty()) {
|
||||||
|
|
||||||
|
// If additional code was passed, add it and reference it in main().
|
||||||
|
//
|
||||||
|
// The function in the additional code is expected to be `vec4 function_name(vec4 color)`.
|
||||||
|
// The texture coordinate can be acquired through `ove_texcoord`.
|
||||||
|
|
||||||
|
frag_code.append(shader_code);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// No function to call
|
||||||
|
function_name = QString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our function_name arg will either resolve to the function added to this or to nothing, in
|
||||||
|
// which case they'll just be benign brackets.
|
||||||
|
frag_code.append(QStringLiteral("\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" vec2 using_texcoord = ove_texcoord;\n"
|
||||||
|
" if (ove_deinterlace) {\n"
|
||||||
|
" // A very basic deinterlace that halves the vertical\n"
|
||||||
|
" // resolution and linearly interpolates the two fields\n"
|
||||||
|
" // by reading the texture coord between them.\n"
|
||||||
|
" float half_vert = round(ove_resolution.y / 2.0);\n"
|
||||||
|
" using_texcoord.y = (round(using_texcoord.y * half_vert) + 0.25) / half_vert;\n"
|
||||||
|
" }\n"
|
||||||
|
" vec4 color = %1(texture(ove_maintex, using_texcoord));\n"
|
||||||
|
" fragColor = color;\n"
|
||||||
|
"}\n").arg(function_name));
|
||||||
|
|
||||||
|
return frag_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenGLShader::CodeDefaultVertex()
|
||||||
|
{
|
||||||
|
// Generate vertex shader
|
||||||
|
return QStringLiteral("#version 150\n"
|
||||||
|
"\n"
|
||||||
|
"#ifdef GL_ES\n"
|
||||||
|
"precision highp int;\n"
|
||||||
|
"precision highp float;\n"
|
||||||
|
"#endif\n"
|
||||||
|
"\n"
|
||||||
|
"uniform mat4 ove_mvpmat;\n"
|
||||||
|
"\n"
|
||||||
|
"in vec4 a_position;\n"
|
||||||
|
"in vec2 a_texcoord;\n"
|
||||||
|
"\n"
|
||||||
|
"out vec2 ove_texcoord;\n"
|
||||||
|
"\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" gl_Position = ove_mvpmat * a_position;\n"
|
||||||
|
" ove_texcoord = a_texcoord;\n"
|
||||||
|
"}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenGLShader::CodeAlphaDisassociate(const QString &function_name)
|
||||||
|
{
|
||||||
|
return QStringLiteral("vec4 %1(vec4 col) {\n"
|
||||||
|
" if (col.a > 0.0) {\n"
|
||||||
|
" return vec4(col.rgb / col.a, col.a);"
|
||||||
|
" }\n"
|
||||||
|
" return col;\n"
|
||||||
|
"}\n").arg(function_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenGLShader::CodeAlphaReassociate(const QString &function_name)
|
||||||
|
{
|
||||||
|
return QStringLiteral("vec4 %1(vec4 col) {\n"
|
||||||
|
" if (col.a > 0.0) {\n"
|
||||||
|
" return vec4(col.rgb * col.a, col.a);"
|
||||||
|
" }\n"
|
||||||
|
" return col;\n"
|
||||||
|
"}\n").arg(function_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenGLShader::CodeAlphaAssociate(const QString &function_name)
|
||||||
|
{
|
||||||
|
return QStringLiteral("vec4 %1(vec4 col) {\n"
|
||||||
|
" return vec4(col.rgb * col.a, col.a);\n"
|
||||||
|
"}\n").arg(function_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_EXIT
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/***
|
||||||
|
|
||||||
|
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 OPENGLSHADER_H
|
||||||
|
#define OPENGLSHADER_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QOpenGLShaderProgram>
|
||||||
|
|
||||||
|
#include <OpenColorIO/OpenColorIO.h>
|
||||||
|
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||||
|
|
||||||
|
#include "common/define.h"
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
|
class OpenGLShader;
|
||||||
|
using OpenGLShaderPtr = std::shared_ptr<OpenGLShader>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A simple QOpenGLShaderProgram derivative with static functions for creating
|
||||||
|
*/
|
||||||
|
class OpenGLShader : public QOpenGLShaderProgram {
|
||||||
|
public:
|
||||||
|
OpenGLShader() = default;
|
||||||
|
|
||||||
|
static OpenGLShaderPtr Create();
|
||||||
|
|
||||||
|
static OpenGLShaderPtr CreateDefault(const QString &function_name = QString(),
|
||||||
|
const QString &shader_code = QString());
|
||||||
|
|
||||||
|
static OpenGLShaderPtr CreateOCIO(QOpenGLContext* ctx,
|
||||||
|
GLuint& lut_texture,
|
||||||
|
OCIO::ConstProcessorRcPtr processor,
|
||||||
|
bool alpha_is_associated);
|
||||||
|
|
||||||
|
static QString CodeDefaultFragment(QString function_name = QString(),
|
||||||
|
const QString &shader_code = QString());
|
||||||
|
static QString CodeDefaultVertex();
|
||||||
|
static QString CodeAlphaDisassociate(const QString& function_name);
|
||||||
|
static QString CodeAlphaReassociate(const QString& function_name);
|
||||||
|
static QString CodeAlphaAssociate(const QString& function_name);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|
||||||
|
#endif // OPENGLSHADER_H
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/***
|
|
||||||
|
|
||||||
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 RENDERCONTEXT_H
|
|
||||||
#define RENDERCONTEXT_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QVariant>
|
|
||||||
|
|
||||||
#include "common/define.h"
|
|
||||||
#include "render/videoparams.h"
|
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
|
||||||
|
|
||||||
class RenderContext : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
RenderContext(QObject* parent = nullptr);
|
|
||||||
|
|
||||||
virtual ~RenderContext() override;
|
|
||||||
|
|
||||||
virtual bool Init() = 0;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
virtual void PostInit() = 0;
|
|
||||||
|
|
||||||
virtual void Destroy() = 0;
|
|
||||||
|
|
||||||
virtual QVariant CreateTexture(const OLIVE_NAMESPACE::VideoParams& param, void* data, int linesize) = 0;
|
|
||||||
|
|
||||||
virtual void DestroyTexture(QVariant texture) = 0;
|
|
||||||
|
|
||||||
virtual void UploadToTexture(QVariant texture, void* data, int linesize) = 0;
|
|
||||||
|
|
||||||
virtual void DownloadFromTexture(QVariant texture, void* data, int linesize) = 0;
|
|
||||||
|
|
||||||
virtual QVariant CreateShader();
|
|
||||||
|
|
||||||
virtual VideoParams GetParamsFromTexture(QVariant texture) = 0;
|
|
||||||
|
|
||||||
QVariant CreateTexture(const OLIVE_NAMESPACE::VideoParams& param);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
|
||||||
|
|
||||||
#endif // RENDERCONTEXT_H
|
|
||||||
@@ -18,19 +18,25 @@
|
|||||||
|
|
||||||
***/
|
***/
|
||||||
|
|
||||||
#include "rendercontext.h"
|
#include "renderer.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
RenderContext::RenderContext(QObject *parent) :
|
Renderer::Renderer(QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant RenderContext::CreateTexture(const VideoParams ¶m)
|
Renderer::TexturePtr Renderer::CreateTexture(const VideoParams ¶m, void *data, int linesize)
|
||||||
{
|
{
|
||||||
return CreateTexture(param, nullptr, 0);
|
QVariant v = CreateNativeTexture(param, data, linesize);
|
||||||
|
|
||||||
|
if (v.isNull()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_shared<Texture>(this, v, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
/***
|
||||||
|
|
||||||
|
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 RENDERCONTEXT_H
|
||||||
|
#define RENDERCONTEXT_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
#include "common/define.h"
|
||||||
|
#include "common/timerange.h"
|
||||||
|
#include "node/node.h"
|
||||||
|
#include "render/colorprocessor.h"
|
||||||
|
#include "render/videoparams.h"
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
|
class Renderer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
Renderer(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
virtual ~Renderer() override;
|
||||||
|
|
||||||
|
virtual bool Init() = 0;
|
||||||
|
|
||||||
|
class Texture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Texture(Renderer* renderer, const QVariant& native, const VideoParams& param) :
|
||||||
|
renderer_(renderer),
|
||||||
|
params_(param),
|
||||||
|
id_(native)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Texture()
|
||||||
|
{
|
||||||
|
renderer_->DestroyNativeTexture(id_);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant id() const
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VideoParams& params() const
|
||||||
|
{
|
||||||
|
return params_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Upload(void* data, int linesize = 0)
|
||||||
|
{
|
||||||
|
renderer_->UploadToTexture(this, data, linesize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int width() const
|
||||||
|
{
|
||||||
|
return params_.width();
|
||||||
|
}
|
||||||
|
|
||||||
|
int height() const
|
||||||
|
{
|
||||||
|
return params_.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelFormat::Format format() const
|
||||||
|
{
|
||||||
|
return params_.format();
|
||||||
|
}
|
||||||
|
|
||||||
|
int divider() const
|
||||||
|
{
|
||||||
|
return params_.divider();
|
||||||
|
}
|
||||||
|
|
||||||
|
const rational& pixel_aspect_ratio() const
|
||||||
|
{
|
||||||
|
return params_.pixel_aspect_ratio();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Renderer* renderer_;
|
||||||
|
|
||||||
|
VideoParams params_;
|
||||||
|
|
||||||
|
QVariant id_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
using TexturePtr = std::shared_ptr<Texture>;
|
||||||
|
|
||||||
|
TexturePtr CreateTexture(const VideoParams& param, void* data = nullptr, int linesize = 0);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void PostInit() = 0;
|
||||||
|
|
||||||
|
virtual void Destroy() = 0;
|
||||||
|
|
||||||
|
virtual QVariant CreateNativeTexture(const VideoParams& param, void* data = nullptr, int linesize = 0) = 0;
|
||||||
|
|
||||||
|
virtual void DestroyNativeTexture(QVariant texture) = 0;
|
||||||
|
|
||||||
|
virtual QVariant CreateNativeShader(const ShaderCode& code) = 0;
|
||||||
|
|
||||||
|
virtual void DestroyNativeShader(QVariant shader) = 0;
|
||||||
|
|
||||||
|
virtual void UploadToTexture(Texture* texture, void* data, int linesize) = 0;
|
||||||
|
|
||||||
|
virtual void DownloadFromTexture(Texture* texture, void* data, int linesize) = 0;
|
||||||
|
|
||||||
|
virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node,
|
||||||
|
const OLIVE_NAMESPACE::TimeRange &range,
|
||||||
|
const OLIVE_NAMESPACE::ShaderJob &job,
|
||||||
|
const OLIVE_NAMESPACE::VideoParams ¶ms) = 0;
|
||||||
|
|
||||||
|
virtual QVariant TransformColor(QVariant texture, OLIVE_NAMESPACE::ColorProcessorPtr processor) = 0;
|
||||||
|
|
||||||
|
virtual void Render() = 0;
|
||||||
|
|
||||||
|
virtual void RenderToTexture(Texture* destination) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|
||||||
|
#endif // RENDERCONTEXT_H
|
||||||
+49
-19
@@ -18,20 +18,25 @@
|
|||||||
|
|
||||||
***/
|
***/
|
||||||
|
|
||||||
#include "rendercontextthreadwrapper.h"
|
#include "rendererthreadwrapper.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
RenderContextThreadWrapper::RenderContextThreadWrapper(RenderContext *inner, QObject *parent) :
|
/*RendererThreadWrapper::RendererThreadWrapper(Renderer *inner, QObject *parent) :
|
||||||
RenderContext(parent),
|
Renderer(parent),
|
||||||
inner_(inner),
|
inner_(inner),
|
||||||
thread_(nullptr)
|
thread_(nullptr)
|
||||||
{
|
{
|
||||||
inner_->setParent(this);
|
inner_->setParent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderContextThreadWrapper::Init()
|
bool RendererThreadWrapper::Init()
|
||||||
{
|
{
|
||||||
|
// Init context in main thread
|
||||||
|
if (!inner_->Init()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Create thread
|
// Create thread
|
||||||
QThread* thread = new QThread(this);
|
QThread* thread = new QThread(this);
|
||||||
thread->start(QThread::IdlePriority);
|
thread->start(QThread::IdlePriority);
|
||||||
@@ -39,17 +44,16 @@ bool RenderContextThreadWrapper::Init()
|
|||||||
// Move context to thread
|
// Move context to thread
|
||||||
inner_->moveToThread(thread);
|
inner_->moveToThread(thread);
|
||||||
|
|
||||||
// Init context in main thread
|
|
||||||
inner_->Init();
|
|
||||||
|
|
||||||
// Queue post-init in new thread
|
// Queue post-init in new thread
|
||||||
QMetaObject::invokeMethod(inner_, "PostInit", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(inner_, "PostInit", Qt::BlockingQueuedConnection);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderContextThreadWrapper::Destroy()
|
void RendererThreadWrapper::Destroy()
|
||||||
{
|
{
|
||||||
if (thread_) {
|
if (thread_) {
|
||||||
QMetaObject::invokeMethod(inner_, "Destroy", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(inner_, "Destroy", Qt::BlockingQueuedConnection);
|
||||||
|
|
||||||
thread_->quit();
|
thread_->quit();
|
||||||
thread_->wait();
|
thread_->wait();
|
||||||
@@ -58,7 +62,7 @@ void RenderContextThreadWrapper::Destroy()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant RenderContextThreadWrapper::CreateTexture(const VideoParams ¶m, void *data, int linesize)
|
QVariant RendererThreadWrapper::CreateTexture(const VideoParams ¶m, void *data, int linesize)
|
||||||
{
|
{
|
||||||
QVariant v;
|
QVariant v;
|
||||||
|
|
||||||
@@ -71,29 +75,55 @@ QVariant RenderContextThreadWrapper::CreateTexture(const VideoParams ¶m, voi
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderContextThreadWrapper::DestroyTexture(QVariant texture)
|
void RendererThreadWrapper::DestroyTexture(QVariant texture)
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(inner_, "DestroyTexture", Qt::QueuedConnection,
|
QMetaObject::invokeMethod(inner_, "DestroyTexture", Qt::BlockingQueuedConnection,
|
||||||
Q_ARG(QVariant, texture));
|
Q_ARG(QVariant, texture));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderContextThreadWrapper::UploadToTexture(QVariant texture, void *data, int linesize)
|
void RendererThreadWrapper::UploadToTexture(QVariant texture, void *data, int linesize)
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(inner_, "UploadToTexture", Qt::QueuedConnection,
|
QMetaObject::invokeMethod(inner_, "UploadToTexture", Qt::BlockingQueuedConnection,
|
||||||
Q_ARG(QVariant, texture),
|
Q_ARG(QVariant, texture),
|
||||||
Q_ARG(void*, data),
|
Q_ARG(void*, data),
|
||||||
Q_ARG(int, linesize));
|
Q_ARG(int, linesize));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderContextThreadWrapper::DownloadFromTexture(QVariant texture, void *data, int linesize)
|
void RendererThreadWrapper::DownloadFromTexture(QVariant texture, void *data, int linesize)
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(inner_, "DownloadFromTexture", Qt::QueuedConnection,
|
QMetaObject::invokeMethod(inner_, "DownloadFromTexture", Qt::BlockingQueuedConnection,
|
||||||
Q_ARG(QVariant, texture),
|
Q_ARG(QVariant, texture),
|
||||||
Q_ARG(void*, data),
|
Q_ARG(void*, data),
|
||||||
Q_ARG(int, linesize));
|
Q_ARG(int, linesize));
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoParams RenderContextThreadWrapper::GetParamsFromTexture(QVariant texture)
|
QVariant RendererThreadWrapper::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job, const VideoParams ¶ms)
|
||||||
|
{
|
||||||
|
QVariant v;
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(inner_, "ProcessShader", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(QVariant, v),
|
||||||
|
OLIVE_NS_CONST_ARG(Node*, node),
|
||||||
|
OLIVE_NS_CONST_ARG(TimeRange&, range),
|
||||||
|
OLIVE_NS_CONST_ARG(ShaderJob&, job),
|
||||||
|
OLIVE_NS_CONST_ARG(VideoParams&, params));
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant RendererThreadWrapper::TransformColor(QVariant texture, ColorProcessorPtr processor)
|
||||||
|
{
|
||||||
|
QVariant v;
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(inner_, "ProcessShader", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(QVariant, v),
|
||||||
|
Q_ARG(QVariant, texture),
|
||||||
|
OLIVE_NS_ARG(ColorProcessorPtr, processor));
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoParams RendererThreadWrapper::GetParamsFromTexture(QVariant texture)
|
||||||
{
|
{
|
||||||
VideoParams p;
|
VideoParams p;
|
||||||
|
|
||||||
@@ -102,6 +132,6 @@ VideoParams RenderContextThreadWrapper::GetParamsFromTexture(QVariant texture)
|
|||||||
Q_ARG(QVariant, texture));
|
Q_ARG(QVariant, texture));
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
+15
-7
@@ -23,16 +23,16 @@
|
|||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
#include "rendercontext.h"
|
#include "renderer.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
class RenderContextThreadWrapper : public RenderContext
|
/*class RendererThreadWrapper : public Renderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RenderContextThreadWrapper(RenderContext* inner, QObject* parent = nullptr);
|
RendererThreadWrapper(Renderer* inner, QObject* parent = nullptr);
|
||||||
|
|
||||||
virtual ~RenderContextThreadWrapper() override
|
virtual ~RendererThreadWrapper() override
|
||||||
{
|
{
|
||||||
Destroy();
|
Destroy();
|
||||||
}
|
}
|
||||||
@@ -52,14 +52,22 @@ public slots:
|
|||||||
|
|
||||||
virtual void DownloadFromTexture(QVariant texture, void* data, int linesize) override;
|
virtual void DownloadFromTexture(QVariant texture, void* data, int linesize) override;
|
||||||
|
|
||||||
virtual VideoParams GetParamsFromTexture(QVariant texture) override;
|
virtual QVariant ProcessShader(const OLIVE_NAMESPACE::Node* node,
|
||||||
|
const OLIVE_NAMESPACE::TimeRange &range,
|
||||||
|
const OLIVE_NAMESPACE::ShaderJob &job,
|
||||||
|
const OLIVE_NAMESPACE::VideoParams ¶ms) override;
|
||||||
|
|
||||||
|
virtual QVariant TransformColor(QVariant texture,
|
||||||
|
OLIVE_NAMESPACE::ColorProcessorPtr processor) override;
|
||||||
|
|
||||||
|
//virtual VideoParams GetParamsFromTexture(QVariant texture) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RenderContext* inner_;
|
Renderer* inner_;
|
||||||
|
|
||||||
QThread* thread_;
|
QThread* thread_;
|
||||||
|
|
||||||
};
|
};*/
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|
||||||
@@ -27,8 +27,8 @@
|
|||||||
|
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "render/backend/opengl/openglcontext.h"
|
#include "render/backend/opengl/openglrenderer.h"
|
||||||
#include "render/backend/rendercontextthreadwrapper.h"
|
#include "render/backend/rendererthreadwrapper.h"
|
||||||
#include "renderprocessor.h"
|
#include "renderprocessor.h"
|
||||||
#include "task/conform/conform.h"
|
#include "task/conform/conform.h"
|
||||||
#include "task/taskmanager.h"
|
#include "task/taskmanager.h"
|
||||||
@@ -41,7 +41,7 @@ RenderManager* RenderManager::instance_ = nullptr;
|
|||||||
RenderManager::RenderManager(QObject *parent) :
|
RenderManager::RenderManager(QObject *parent) :
|
||||||
ThreadPool(QThread::IdlePriority, 0, parent)
|
ThreadPool(QThread::IdlePriority, 0, parent)
|
||||||
{
|
{
|
||||||
context_ = new RenderContextThreadWrapper(new OpenGLContext(), this);
|
context_ = new RendererThreadWrapper(new OpenGLRenderer(), this);
|
||||||
context_->Init();
|
context_->Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
#include "node/graph.h"
|
#include "node/graph.h"
|
||||||
#include "node/output/viewer/viewer.h"
|
#include "node/output/viewer/viewer.h"
|
||||||
#include "node/traverser.h"
|
#include "node/traverser.h"
|
||||||
#include "render/backend/rendercontext.h"
|
#include "render/backend/renderer.h"
|
||||||
#include "threading/threadpool.h"
|
#include "threading/threadpool.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
@@ -111,12 +111,12 @@ private:
|
|||||||
|
|
||||||
static RenderManager* instance_;
|
static RenderManager* instance_;
|
||||||
|
|
||||||
RenderContext* context_;
|
Renderer* context_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(RenderManager::TicketType);
|
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::RenderManager::TicketType);
|
||||||
|
|
||||||
#endif // RENDERBACKEND_H
|
#endif // RENDERBACKEND_H
|
||||||
|
|||||||
+12
-239
@@ -20,11 +20,15 @@
|
|||||||
|
|
||||||
#include "renderprocessor.h"
|
#include "renderprocessor.h"
|
||||||
|
|
||||||
|
#include <QVector2D>
|
||||||
|
#include <QVector3D>
|
||||||
|
#include <QVector4D>
|
||||||
|
|
||||||
#include "rendermanager.h"
|
#include "rendermanager.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
RenderProcessor::RenderProcessor(RenderTicketPtr ticket, RenderContext *render_ctx) :
|
RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx) :
|
||||||
ticket_(ticket),
|
ticket_(ticket),
|
||||||
render_ctx_(render_ctx)
|
render_ctx_(render_ctx)
|
||||||
{
|
{
|
||||||
@@ -46,7 +50,7 @@ void RenderProcessor::Run()
|
|||||||
NodeValueTable table = ProcessInput(viewer->texture_input(),
|
NodeValueTable table = ProcessInput(viewer->texture_input(),
|
||||||
TimeRange(time, time + viewer->video_params().time_base()));
|
TimeRange(time, time + viewer->video_params().time_base()));
|
||||||
|
|
||||||
QVariant texture = table.Get(NodeParam::kTexture);
|
Renderer::TexturePtr texture = table.Get(NodeParam::kTexture).value<Renderer::TexturePtr>();
|
||||||
|
|
||||||
QSize frame_size = ticket_->property("size").value<QSize>();
|
QSize frame_size = ticket_->property("size").value<QSize>();
|
||||||
if (frame_size.isNull()) {
|
if (frame_size.isNull()) {
|
||||||
@@ -65,18 +69,18 @@ void RenderProcessor::Run()
|
|||||||
viewer->video_params().divider()));
|
viewer->video_params().divider()));
|
||||||
frame->allocate();
|
frame->allocate();
|
||||||
|
|
||||||
if (texture.isNull()) {
|
if (!texture) {
|
||||||
// Blank frame out
|
// Blank frame out
|
||||||
memset(frame->data(), 0, frame->allocated_size());
|
memset(frame->data(), 0, frame->allocated_size());
|
||||||
} else {
|
} else {
|
||||||
// Dump texture contents to frame
|
// Dump texture contents to frame
|
||||||
VideoParams tex_params = render_ctx_->GetParamsFromTexture(texture);
|
const VideoParams& tex_params = texture->params();
|
||||||
|
|
||||||
if (tex_params.width() != frame->width() || tex_params.height() != frame->height()) {
|
if (tex_params.width() != frame->width() || tex_params.height() != frame->height()) {
|
||||||
// FIXME: Blit this shit
|
// FIXME: Blit this shit
|
||||||
}
|
}
|
||||||
|
|
||||||
render_ctx_->DownloadFromTexture(texture, frame->data(), frame->linesize_pixels());
|
render_ctx_->DownloadFromTexture(texture.get(), frame->data(), frame->linesize_pixels());
|
||||||
}
|
}
|
||||||
|
|
||||||
ticket_->Finish(QVariant::fromValue(frame), IsCancelled());
|
ticket_->Finish(QVariant::fromValue(frame), IsCancelled());
|
||||||
@@ -109,7 +113,7 @@ void RenderProcessor::Run()
|
|||||||
this->deleteLater();
|
this->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderProcessor::Process(RenderTicketPtr ticket, RenderContext *render_ctx)
|
void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx)
|
||||||
{
|
{
|
||||||
RenderProcessor p(ticket, render_ctx);
|
RenderProcessor p(ticket, render_ctx);
|
||||||
p.Run();
|
p.Run();
|
||||||
@@ -293,240 +297,9 @@ QVariant RenderProcessor::ProcessAudioFootage(StreamPtr stream, const TimeRange
|
|||||||
|
|
||||||
QVariant RenderProcessor::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job)
|
QVariant RenderProcessor::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job)
|
||||||
{
|
{
|
||||||
// If this node is iterative, we'll pick up which input here
|
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
|
||||||
GLuint iterative_input = 0;
|
|
||||||
QList<GLuint> textures_to_bind;
|
|
||||||
bool input_textures_have_alpha = false;
|
|
||||||
|
|
||||||
OpenGLShaderPtr shader = ResolveShaderFromCache(node, job.GetShaderID());
|
render_ctx_->ProcessShader(node, range, job, video_params);
|
||||||
|
|
||||||
if (!shader) {
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
shader->bind();
|
|
||||||
|
|
||||||
NodeValueMap::const_iterator it;
|
|
||||||
for (it=job.GetValues().constBegin(); it!=job.GetValues().constEnd(); it++) {
|
|
||||||
// See if the shader has takes this parameter as an input
|
|
||||||
int variable_location = shader->uniformLocation(it.key());
|
|
||||||
|
|
||||||
if (variable_location == -1) {
|
|
||||||
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();
|
|
||||||
|
|
||||||
NodeParam::DataType data_type = (it.value().type() != NodeParam::kNone)
|
|
||||||
? it.value().type()
|
|
||||||
: corresponding_input->data_type();
|
|
||||||
|
|
||||||
switch (data_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());
|
|
||||||
break;
|
|
||||||
case NodeInput::kFloat:
|
|
||||||
// kFloat technically specifies a double but as above, OpenGL doesn't support those.
|
|
||||||
shader->setUniformValue(variable_location, value.toFloat());
|
|
||||||
break;
|
|
||||||
case NodeInput::kVec2:
|
|
||||||
if (corresponding_input && corresponding_input->IsArray()) {
|
|
||||||
QVector<NodeValue> nv = value.value< QVector<NodeValue> >();
|
|
||||||
QVector<QVector2D> a(nv.size());
|
|
||||||
|
|
||||||
for (int j=0;j<a.size();j++) {
|
|
||||||
a[j] = nv.at(j).data().value<QVector2D>();
|
|
||||||
}
|
|
||||||
|
|
||||||
shader->setUniformValueArray(variable_location, a.constData(), a.size());
|
|
||||||
|
|
||||||
int count_location = shader->uniformLocation(QStringLiteral("%1_count").arg(it.key()));
|
|
||||||
if (count_location > -1) {
|
|
||||||
shader->setUniformValue(count_location, a.size());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
shader->setUniformValue(variable_location, value.value<QVector2D>());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NodeInput::kVec3:
|
|
||||||
shader->setUniformValue(variable_location, value.value<QVector3D>());
|
|
||||||
break;
|
|
||||||
case NodeInput::kVec4:
|
|
||||||
shader->setUniformValue(variable_location, value.value<QVector4D>());
|
|
||||||
break;
|
|
||||||
case NodeInput::kMatrix:
|
|
||||||
shader->setUniformValue(variable_location, value.value<QMatrix4x4>());
|
|
||||||
break;
|
|
||||||
case NodeInput::kCombo:
|
|
||||||
shader->setUniformValue(variable_location, value.value<int>());
|
|
||||||
break;
|
|
||||||
case NodeInput::kColor:
|
|
||||||
{
|
|
||||||
Color color = value.value<Color>();
|
|
||||||
|
|
||||||
shader->setUniformValue(variable_location, color.red(), color.green(), color.blue(), color.alpha());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NodeInput::kBoolean:
|
|
||||||
shader->setUniformValue(variable_location, value.toBool());
|
|
||||||
break;
|
|
||||||
case NodeInput::kBuffer:
|
|
||||||
case NodeInput::kTexture:
|
|
||||||
{
|
|
||||||
OpenGLTextureCache::ReferencePtr texture = value.value<OpenGLTextureCache::ReferencePtr>();
|
|
||||||
|
|
||||||
if (texture) {
|
|
||||||
if (PixelFormat::FormatHasAlphaChannel(texture->texture()->format())) {
|
|
||||||
input_textures_have_alpha = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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()) {
|
|
||||||
iterative_input = textures_to_bind.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint tex_id = texture ? texture->texture()->texture() : 0;
|
|
||||||
textures_to_bind.append(tex_id);
|
|
||||||
|
|
||||||
// Set enable flag if shader wants it
|
|
||||||
int enable_param_location = shader->uniformLocation(QStringLiteral("%1_enabled").arg(it.key()));
|
|
||||||
if (enable_param_location > -1) {
|
|
||||||
shader->setUniformValue(enable_param_location,
|
|
||||||
tex_id > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tex_id > 0) {
|
|
||||||
// Set texture resolution if shader wants it
|
|
||||||
int res_param_location = shader->uniformLocation(QStringLiteral("%1_resolution").arg(it.key()));
|
|
||||||
if (res_param_location > -1) {
|
|
||||||
int adjusted_width = texture->texture()->width() * texture->texture()->divider();
|
|
||||||
|
|
||||||
// Adjust virtual width by pixel aspect if necessary
|
|
||||||
if (texture->texture()->params().pixel_aspect_ratio() != 1
|
|
||||||
|| params.pixel_aspect_ratio() != 1) {
|
|
||||||
double relative_pixel_aspect = texture->texture()->params().pixel_aspect_ratio().toDouble() / params.pixel_aspect_ratio().toDouble();
|
|
||||||
|
|
||||||
adjusted_width = qRound(static_cast<double>(adjusted_width) * relative_pixel_aspect);
|
|
||||||
}
|
|
||||||
|
|
||||||
shader->setUniformValue(res_param_location,
|
|
||||||
adjusted_width,
|
|
||||||
static_cast<GLfloat>(texture->texture()->height() * texture->texture()->divider()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NodeInput::kSamples:
|
|
||||||
case NodeInput::kText:
|
|
||||||
case NodeInput::kRational:
|
|
||||||
case NodeInput::kFont:
|
|
||||||
case NodeInput::kFile:
|
|
||||||
case NodeInput::kDecimal:
|
|
||||||
case NodeInput::kNumber:
|
|
||||||
case NodeInput::kString:
|
|
||||||
case NodeInput::kVector:
|
|
||||||
case NodeInput::kShaderJob:
|
|
||||||
case NodeInput::kSampleJob:
|
|
||||||
case NodeInput::kGenerateJob:
|
|
||||||
case NodeInput::kFootage:
|
|
||||||
case NodeInput::kNone:
|
|
||||||
case NodeInput::kAny:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide some standard args
|
|
||||||
shader->setUniformValue("ove_resolution",
|
|
||||||
static_cast<GLfloat>(params.width()),
|
|
||||||
static_cast<GLfloat>(params.height()));
|
|
||||||
|
|
||||||
shader->release();
|
|
||||||
|
|
||||||
// Create the output textures
|
|
||||||
PixelFormat::Format output_format = (input_textures_have_alpha || job.GetAlphaChannelRequired())
|
|
||||||
? PixelFormat::GetFormatWithAlphaChannel(params.format())
|
|
||||||
: PixelFormat::GetFormatWithoutAlphaChannel(params.format());
|
|
||||||
VideoParams output_params(params.width(),
|
|
||||||
params.height(),
|
|
||||||
params.time_base(),
|
|
||||||
output_format,
|
|
||||||
params.pixel_aspect_ratio(),
|
|
||||||
params.interlacing(),
|
|
||||||
params.divider());
|
|
||||||
|
|
||||||
int real_iteration_count;
|
|
||||||
if (job.GetIterationCount() > 1 && job.GetIterativeInput()) {
|
|
||||||
real_iteration_count = job.GetIterationCount();
|
|
||||||
} else {
|
|
||||||
real_iteration_count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenGLTextureCache::ReferencePtr dst_refs[2];
|
|
||||||
dst_refs[0] = texture_cache_.Get(ctx_, output_params);
|
|
||||||
|
|
||||||
// If this node requires multiple iterations, get a texture for it too
|
|
||||||
if (real_iteration_count > 1) {
|
|
||||||
dst_refs[1] = texture_cache_.Get(ctx_, output_params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some nodes use multiple iterations for optimization
|
|
||||||
OpenGLTextureCache::ReferencePtr input_tex, output_tex;
|
|
||||||
|
|
||||||
// Set up OpenGL parameters as necessary
|
|
||||||
functions_->glViewport(0, 0, params.effective_width(), params.effective_height());
|
|
||||||
|
|
||||||
// Bind all textures
|
|
||||||
for (int i=0; i<textures_to_bind.size(); i++) {
|
|
||||||
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
|
||||||
functions_->glBindTexture(GL_TEXTURE_2D, textures_to_bind.at(i));
|
|
||||||
OpenGLRenderFunctions::PrepareToDraw(functions_);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int iteration=0; iteration<real_iteration_count; iteration++) {
|
|
||||||
// Set iteration number
|
|
||||||
shader->bind();
|
|
||||||
shader->setUniformValue("ove_iteration", iteration);
|
|
||||||
shader->release();
|
|
||||||
|
|
||||||
// Replace iterative input
|
|
||||||
if (iteration == 0) {
|
|
||||||
output_tex = dst_refs[0];
|
|
||||||
} else {
|
|
||||||
input_tex = dst_refs[(iteration+1)%2];
|
|
||||||
output_tex = dst_refs[iteration%2];
|
|
||||||
|
|
||||||
functions_->glActiveTexture(GL_TEXTURE0 + iterative_input);
|
|
||||||
functions_->glBindTexture(GL_TEXTURE_2D, input_tex->texture()->texture());
|
|
||||||
OpenGLRenderFunctions::PrepareToDraw(functions_);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_.Attach(output_tex->texture(), true);
|
|
||||||
buffer_.Bind();
|
|
||||||
|
|
||||||
// Blit this texture through this shader
|
|
||||||
OpenGLRenderFunctions::Blit(shader);
|
|
||||||
|
|
||||||
buffer_.Release();
|
|
||||||
buffer_.Detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release any textures we bound before
|
|
||||||
for (int i=textures_to_bind.size()-1; i>=0; i--) {
|
|
||||||
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
|
||||||
functions_->glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return QVariant::fromValue(output_tex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant RenderProcessor::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job)
|
QVariant RenderProcessor::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job)
|
||||||
|
|||||||
@@ -22,16 +22,16 @@
|
|||||||
#define RENDERPROCESSOR_H
|
#define RENDERPROCESSOR_H
|
||||||
|
|
||||||
#include "node/traverser.h"
|
#include "node/traverser.h"
|
||||||
#include "render/backend/rendercontext.h"
|
#include "render/backend/renderer.h"
|
||||||
#include "threading/threadticket.h"
|
#include "threading/threadticket.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
class RenderProcessor : public NodeTraverser, public QObject
|
class RenderProcessor : public QObject, public NodeTraverser
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static void Process(RenderTicketPtr ticket, RenderContext* render_ctx);
|
static void Process(RenderTicketPtr ticket, Renderer* render_ctx);
|
||||||
|
|
||||||
struct RenderedWaveform {
|
struct RenderedWaveform {
|
||||||
const TrackOutput* track;
|
const TrackOutput* track;
|
||||||
@@ -60,16 +60,18 @@ protected:
|
|||||||
virtual QVariant GetCachedFrame(const Node *node, const rational &time) override;
|
virtual QVariant GetCachedFrame(const Node *node, const rational &time) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RenderProcessor(RenderTicketPtr ticket, RenderContext* render_ctx);
|
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx);
|
||||||
|
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
RenderTicketPtr ticket_;
|
RenderTicketPtr ticket_;
|
||||||
|
|
||||||
RenderContext* render_ctx_;
|
Renderer* render_ctx_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::RenderProcessor::RenderedWaveform);
|
||||||
|
|
||||||
#endif // RENDERPROCESSOR_H
|
#endif // RENDERPROCESSOR_H
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "render/backend/opengl/openglrenderer.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
ManagedDisplayWidget::ManagedDisplayWidget(QWidget *parent) :
|
ManagedDisplayWidget::ManagedDisplayWidget(QWidget *parent) :
|
||||||
@@ -30,6 +32,8 @@ ManagedDisplayWidget::ManagedDisplayWidget(QWidget *parent) :
|
|||||||
color_service_(nullptr)
|
color_service_(nullptr)
|
||||||
{
|
{
|
||||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
|
attached_renderer_ = new OpenGLRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
ManagedDisplayWidget::~ManagedDisplayWidget()
|
ManagedDisplayWidget::~ManagedDisplayWidget()
|
||||||
@@ -102,7 +106,7 @@ void ManagedDisplayWidget::ColorConfigChanged()
|
|||||||
SetColorTransform(color_manager_->GetCompliantColorSpace(color_transform_, true));
|
SetColorTransform(color_manager_->GetCompliantColorSpace(color_transform_, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLColorProcessorPtr ManagedDisplayWidget::color_service()
|
ColorProcessorPtr ManagedDisplayWidget::color_service()
|
||||||
{
|
{
|
||||||
return color_service_;
|
return color_service_;
|
||||||
}
|
}
|
||||||
@@ -113,6 +117,8 @@ void ManagedDisplayWidget::ContextCleanup()
|
|||||||
|
|
||||||
color_service_ = nullptr;
|
color_service_ = nullptr;
|
||||||
|
|
||||||
|
attached_renderer_->Destroy();
|
||||||
|
|
||||||
doneCurrent();
|
doneCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +194,8 @@ void ManagedDisplayWidget::initializeGL()
|
|||||||
SetupColorProcessor();
|
SetupColorProcessor();
|
||||||
|
|
||||||
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ManagedDisplayWidget::ContextCleanup, Qt::DirectConnection);
|
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ManagedDisplayWidget::ContextCleanup, Qt::DirectConnection);
|
||||||
|
|
||||||
|
static_cast<OpenGLRenderer*>(attached_renderer_)->Init(context());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ManagedDisplayWidget::EnableDefaultContextMenu()
|
void ManagedDisplayWidget::EnableDefaultContextMenu()
|
||||||
@@ -280,11 +288,9 @@ void ManagedDisplayWidget::SetupColorProcessor()
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
color_service_ = OpenGLColorProcessor::Create(color_manager_,
|
color_service_ = ColorProcessor::Create(color_manager_,
|
||||||
color_manager_->GetReferenceColorSpace(),
|
color_manager_->GetReferenceColorSpace(),
|
||||||
color_transform_);
|
color_transform_);
|
||||||
|
|
||||||
color_service_->Enable(context(), true);
|
|
||||||
|
|
||||||
} catch (OCIO::Exception& e) {
|
} catch (OCIO::Exception& e) {
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
|
|
||||||
#include "render/backend/opengl/openglcolorprocessor.h"
|
#include "render/backend/renderer.h"
|
||||||
#include "render/colormanager.h"
|
#include "render/colormanager.h"
|
||||||
#include "widget/menu/menu.h"
|
#include "widget/menu/menu.h"
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ protected:
|
|||||||
/**
|
/**
|
||||||
* @brief Provides access to the color processor (nullptr if none is set)
|
* @brief Provides access to the color processor (nullptr if none is set)
|
||||||
*/
|
*/
|
||||||
OpenGLColorProcessorPtr color_service();
|
ColorProcessorPtr color_service();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Override when setting up OpenGL context
|
* @brief Override when setting up OpenGL context
|
||||||
@@ -128,6 +128,11 @@ private:
|
|||||||
*/
|
*/
|
||||||
void ClearOCIOLutTexture();
|
void ClearOCIOLutTexture();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Renderer abstraction
|
||||||
|
*/
|
||||||
|
Renderer* attached_renderer_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Connected color manager
|
* @brief Connected color manager
|
||||||
*/
|
*/
|
||||||
@@ -136,7 +141,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* @brief Color management service
|
* @brief Color management service
|
||||||
*/
|
*/
|
||||||
OpenGLColorProcessorPtr color_service_;
|
ColorProcessorPtr color_service_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Internal color transform storage
|
* @brief Internal color transform storage
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
#include "common/qtutils.h"
|
#include "common/qtutils.h"
|
||||||
#include "node/node.h"
|
#include "node/node.h"
|
||||||
#include "render/backend/opengl/openglrenderfunctions.h"
|
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
@@ -75,7 +74,7 @@ void HistogramScope::CleanUp()
|
|||||||
doneCurrent();
|
doneCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLShaderPtr HistogramScope::CreateShader()
|
QVariant HistogramScope::CreateShader()
|
||||||
{
|
{
|
||||||
OpenGLShaderPtr pipeline = OpenGLShader::Create();
|
OpenGLShaderPtr pipeline = OpenGLShader::Create();
|
||||||
|
|
||||||
|
|||||||
@@ -36,16 +36,16 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
virtual void initializeGL() override;
|
virtual void initializeGL() override;
|
||||||
|
|
||||||
virtual OpenGLShaderPtr CreateShader() override;
|
virtual QVariant CreateShader() override;
|
||||||
OpenGLShaderPtr CreateSecondaryShader();
|
QVariant CreateSecondaryShader();
|
||||||
|
|
||||||
void AssertAdditionalTextures();
|
void AssertAdditionalTextures();
|
||||||
|
|
||||||
virtual void DrawScope() override;
|
virtual void DrawScope() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OpenGLShaderPtr pipeline_secondary_;
|
QVariant pipeline_secondary_;
|
||||||
OpenGLTexture texture_row_sums_;
|
QVariant texture_row_sums_;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void CleanUp();
|
void CleanUp();
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ void ScopeBase::showEvent(QShowEvent* e)
|
|||||||
UploadTextureFromBuffer();
|
UploadTextureFromBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLShaderPtr ScopeBase::CreateShader()
|
QVariant ScopeBase::CreateShader()
|
||||||
{
|
{
|
||||||
return OpenGLShader::CreateDefault();
|
return OpenGLShader::CreateDefault();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,7 @@
|
|||||||
#define SCOPEBASE_H
|
#define SCOPEBASE_H
|
||||||
|
|
||||||
#include "codec/frame.h"
|
#include "codec/frame.h"
|
||||||
#include "render/backend/opengl/openglcolorprocessor.h"
|
#include "render/colorprocessor.h"
|
||||||
#include "render/backend/opengl/openglframebuffer.h"
|
|
||||||
#include "render/backend/opengl/openglshader.h"
|
|
||||||
#include "render/backend/opengl/opengltexture.h"
|
|
||||||
#include "widget/manageddisplay/manageddisplay.h"
|
#include "widget/manageddisplay/manageddisplay.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
@@ -47,35 +44,28 @@ protected:
|
|||||||
|
|
||||||
virtual void showEvent(QShowEvent* e) override;
|
virtual void showEvent(QShowEvent* e) override;
|
||||||
|
|
||||||
virtual OpenGLShaderPtr CreateShader();
|
virtual QVariant CreateShader();
|
||||||
|
|
||||||
virtual void DrawScope();
|
virtual void DrawScope();
|
||||||
|
|
||||||
OpenGLShaderPtr pipeline()
|
QVariant pipeline()
|
||||||
{
|
{
|
||||||
return pipeline_;
|
return pipeline_;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLTexture& managed_tex()
|
QVariant managed_tex()
|
||||||
{
|
{
|
||||||
return managed_tex_;
|
return managed_tex_;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLFramebuffer& framebuffer()
|
|
||||||
{
|
|
||||||
return framebuffer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UploadTextureFromBuffer();
|
void UploadTextureFromBuffer();
|
||||||
|
|
||||||
OpenGLShaderPtr pipeline_;
|
QVariant pipeline_;
|
||||||
|
|
||||||
OpenGLTexture texture_;
|
QVariant texture_;
|
||||||
|
|
||||||
OpenGLTexture managed_tex_;
|
QVariant managed_tex_;
|
||||||
|
|
||||||
OpenGLFramebuffer framebuffer_;
|
|
||||||
|
|
||||||
Frame* buffer_;
|
Frame* buffer_;
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,7 @@
|
|||||||
|
|
||||||
#include "node/node.h"
|
#include "node/node.h"
|
||||||
#include "render/backend/opengl/openglcolorprocessor.h"
|
#include "render/backend/opengl/openglcolorprocessor.h"
|
||||||
#include "render/backend/opengl/openglframebuffer.h"
|
|
||||||
#include "render/backend/opengl/openglshader.h"
|
#include "render/backend/opengl/openglshader.h"
|
||||||
#include "render/backend/opengl/opengltexture.h"
|
|
||||||
#include "render/color.h"
|
#include "render/color.h"
|
||||||
#include "render/colormanager.h"
|
#include "render/colormanager.h"
|
||||||
#include "tool/tool.h"
|
#include "tool/tool.h"
|
||||||
@@ -211,7 +209,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL().
|
* @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL().
|
||||||
*/
|
*/
|
||||||
OpenGLTexture texture_;
|
QVariant texture_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Translation only matrix (defaults to identity).
|
* @brief Translation only matrix (defaults to identity).
|
||||||
|
|||||||
Reference in New Issue
Block a user