began rewrite of renderer inner workings
This commit is contained in:
@@ -18,5 +18,9 @@ add_subdirectory(opengl)
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
render/backend/rendercontext.cpp
|
||||
render/backend/rendercontext.h
|
||||
render/backend/rendercontextthreadwrapper.cpp
|
||||
render/backend/rendercontextthreadwrapper.h
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -16,19 +16,7 @@
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
render/backend/opengl/openglcolorprocessor.h
|
||||
render/backend/opengl/openglcolorprocessor.cpp
|
||||
render/backend/opengl/openglframebuffer.h
|
||||
render/backend/opengl/openglframebuffer.cpp
|
||||
render/backend/opengl/openglproxy.h
|
||||
render/backend/opengl/openglproxy.cpp
|
||||
render/backend/opengl/openglrenderfunctions.h
|
||||
render/backend/opengl/openglrenderfunctions.cpp
|
||||
render/backend/opengl/openglshader.h
|
||||
render/backend/opengl/openglshader.cpp
|
||||
render/backend/opengl/opengltexture.h
|
||||
render/backend/opengl/opengltexture.cpp
|
||||
render/backend/opengl/opengltexturecache.h
|
||||
render/backend/opengl/opengltexturecache.cpp
|
||||
render/backend/opengl/openglcontext.cpp
|
||||
render/backend/opengl/openglcontext.h
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -1,90 +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 "openglcolorprocessor.h"
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
#include "openglrenderfunctions.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
void OpenGLColorProcessor::Enable(QOpenGLContext *context, bool alpha_is_associated)
|
||||
{
|
||||
if (IsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
context_ = context;
|
||||
|
||||
pipeline_ = OpenGLShader::CreateOCIO(context_,
|
||||
ocio_lut_,
|
||||
GetProcessor(),
|
||||
alpha_is_associated);
|
||||
|
||||
connect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLColorProcessor::ClearTexture, Qt::DirectConnection);
|
||||
}
|
||||
|
||||
bool OpenGLColorProcessor::IsEnabled() const
|
||||
{
|
||||
return ocio_lut_;
|
||||
}
|
||||
|
||||
OpenGLShaderPtr OpenGLColorProcessor::pipeline() const
|
||||
{
|
||||
return pipeline_;
|
||||
}
|
||||
|
||||
void OpenGLColorProcessor::ProcessOpenGL(bool flipped, const QMatrix4x4& matrix)
|
||||
{
|
||||
OpenGLRenderFunctions::OCIOBlit(pipeline_, ocio_lut_, flipped, matrix);
|
||||
}
|
||||
|
||||
void OpenGLColorProcessor::ClearTexture()
|
||||
{
|
||||
if (IsEnabled()) {
|
||||
// Clean up OCIO LUT texture and shader
|
||||
context_->functions()->glDeleteTextures(1, &ocio_lut_);
|
||||
|
||||
disconnect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLColorProcessor::ClearTexture);
|
||||
|
||||
ocio_lut_ = 0;
|
||||
pipeline_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLColorProcessor::OpenGLColorProcessor(ColorManager* config, const QString &source_space, const ColorTransform &dest_space) :
|
||||
ColorProcessor(config, source_space, dest_space),
|
||||
ocio_lut_(0)
|
||||
{
|
||||
}
|
||||
|
||||
OpenGLColorProcessor::~OpenGLColorProcessor()
|
||||
{
|
||||
ClearTexture();
|
||||
}
|
||||
|
||||
OpenGLColorProcessorPtr OpenGLColorProcessor::Create(ColorManager *config, const QString &source_space, const ColorTransform &dest_space)
|
||||
{
|
||||
return std::make_shared<OpenGLColorProcessor>(config, source_space, dest_space);
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -1,69 +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 OPENGLCOLORPROCESSOR_H
|
||||
#define OPENGLCOLORPROCESSOR_H
|
||||
|
||||
#include "openglshader.h"
|
||||
#include "render/colorprocessor.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class OpenGLColorProcessor;
|
||||
using OpenGLColorProcessorPtr = std::shared_ptr<OpenGLColorProcessor>;
|
||||
|
||||
class OpenGLColorProcessor : public QObject, public ColorProcessor
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OpenGLColorProcessor(ColorManager *config,
|
||||
const QString& input,
|
||||
const ColorTransform& dest);
|
||||
|
||||
virtual ~OpenGLColorProcessor() override;
|
||||
|
||||
static OpenGLColorProcessorPtr Create(ColorManager* config,
|
||||
const QString& input,
|
||||
const ColorTransform& dest);
|
||||
|
||||
void Enable(QOpenGLContext* context, bool alpha_is_associated);
|
||||
bool IsEnabled() const;
|
||||
|
||||
OpenGLShaderPtr pipeline() const;
|
||||
|
||||
void ProcessOpenGL(bool flipped = false, const QMatrix4x4& matrix = QMatrix4x4());
|
||||
|
||||
private:
|
||||
QOpenGLContext* context_;
|
||||
|
||||
GLuint ocio_lut_;
|
||||
|
||||
OpenGLShaderPtr pipeline_;
|
||||
|
||||
private slots:
|
||||
void ClearTexture();
|
||||
|
||||
};
|
||||
|
||||
using OpenGLColorProcessorCache = QHash<QString, OpenGLColorProcessorPtr>;
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // OPENGLCOLORPROCESSOR_H
|
||||
@@ -0,0 +1,195 @@
|
||||
/***
|
||||
|
||||
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,76 @@
|
||||
/***
|
||||
|
||||
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 OPENGLCONTEXT_H
|
||||
#define OPENGLCONTEXT_H
|
||||
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QThread>
|
||||
|
||||
#include "render/backend/rendercontext.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class OpenGLContext : public RenderContext
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OpenGLContext(QObject* parent = nullptr);
|
||||
|
||||
virtual ~OpenGLContext() override;
|
||||
|
||||
virtual bool Init() override;
|
||||
|
||||
public slots:
|
||||
virtual void PostInit() override;
|
||||
|
||||
virtual void Destroy() override;
|
||||
|
||||
virtual QVariant CreateTexture(const VideoParams& param, void* data, int linesize) override;
|
||||
|
||||
virtual void DestroyTexture(QVariant texture) override;
|
||||
|
||||
virtual void UploadToTexture(QVariant texture, void* data, int linesize) override;
|
||||
|
||||
virtual void DownloadFromTexture(QVariant texture, void* data, int linesize) override;
|
||||
|
||||
virtual VideoParams GetParamsFromTexture(QVariant texture) override;
|
||||
|
||||
private:
|
||||
static GLint GetInternalFormat(PixelFormat::Format format);
|
||||
|
||||
static GLenum GetPixelFormat(PixelFormat::Format format);
|
||||
|
||||
static GLenum GetPixelType(PixelFormat::Format format);
|
||||
|
||||
QOpenGLContext* context_;
|
||||
|
||||
QOpenGLFunctions* functions_;
|
||||
|
||||
QOffscreenSurface surface_;
|
||||
|
||||
QMap<GLuint, VideoParams> texture_params_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // OPENGLCONTEXT_H
|
||||
@@ -1,153 +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 "openglframebuffer.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QOpenGLExtraFunctions>
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
OpenGLFramebuffer::OpenGLFramebuffer() :
|
||||
context_(nullptr),
|
||||
buffer_(0),
|
||||
texture_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
OpenGLFramebuffer::~OpenGLFramebuffer()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Create(QOpenGLContext *ctx)
|
||||
{
|
||||
if (ctx == nullptr) {
|
||||
qWarning() << "OpenGLFramebuffer::Create was passed an invalid context";
|
||||
return;
|
||||
}
|
||||
|
||||
// Free any previous framebuffer
|
||||
Destroy();
|
||||
|
||||
context_ = ctx;
|
||||
|
||||
connect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLFramebuffer::Destroy);
|
||||
|
||||
// Create framebuffer object
|
||||
context_->functions()->glGenFramebuffers(1, &buffer_);
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Destroy()
|
||||
{
|
||||
if (context_ != nullptr) {
|
||||
disconnect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLFramebuffer::Destroy);
|
||||
|
||||
context_->functions()->glDeleteFramebuffers(1, &buffer_);
|
||||
|
||||
buffer_ = 0;
|
||||
|
||||
context_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenGLFramebuffer::IsCreated() const
|
||||
{
|
||||
return (buffer_ > 0);
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Bind()
|
||||
{
|
||||
if (context_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
context_->functions()->glBindFramebuffer(GL_FRAMEBUFFER, buffer_);
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Release()
|
||||
{
|
||||
if (context_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
context_->functions()->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Attach(OpenGLTexture *texture, bool clear)
|
||||
{
|
||||
if (context_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Detach();
|
||||
|
||||
texture_ = texture;
|
||||
|
||||
QOpenGLFunctions* f = context_->functions();
|
||||
|
||||
// bind framebuffer for attaching
|
||||
f->glBindFramebuffer(GL_FRAMEBUFFER, buffer_);
|
||||
|
||||
context_->extraFunctions()->glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_->texture(), 0
|
||||
);
|
||||
|
||||
if (clear) {
|
||||
context_->functions()->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
context_->functions()->glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// release framebuffer
|
||||
f->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Attach(OpenGLTexturePtr texture, bool clear)
|
||||
{
|
||||
Attach(texture.get(), clear);
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Detach()
|
||||
{
|
||||
if (context_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (texture_) {
|
||||
QOpenGLFunctions* f = context_->functions();
|
||||
|
||||
// bind framebuffer for attaching
|
||||
f->glBindFramebuffer(GL_FRAMEBUFFER, buffer_);
|
||||
|
||||
context_->extraFunctions()->glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0
|
||||
);
|
||||
|
||||
// release framebuffer
|
||||
f->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
texture_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const GLuint &OpenGLFramebuffer::buffer() const
|
||||
{
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -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 OPENGLFRAMEBUFFER_H
|
||||
#define OPENGLFRAMEBUFFER_H
|
||||
|
||||
#include <QOpenGLContext>
|
||||
|
||||
#include "opengltexture.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class OpenGLFramebuffer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OpenGLFramebuffer();
|
||||
virtual ~OpenGLFramebuffer() override;
|
||||
|
||||
void Create(QOpenGLContext *ctx);
|
||||
|
||||
bool IsCreated() const;
|
||||
|
||||
void Bind();
|
||||
|
||||
void Release();
|
||||
|
||||
void Attach(OpenGLTexture* texture, bool clear = false);
|
||||
void Attach(OpenGLTexturePtr texture, bool clear = false);
|
||||
|
||||
void Detach();
|
||||
|
||||
const GLuint& buffer() const;
|
||||
|
||||
public slots:
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
QOpenGLContext* context_;
|
||||
|
||||
GLuint buffer_;
|
||||
|
||||
OpenGLTexture* texture_;
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // OPENGLFRAMEBUFFER_H
|
||||
@@ -1,567 +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 "openglproxy.h"
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#include "common/clamp.h"
|
||||
#include "core.h"
|
||||
#include "node/block/transition/transition.h"
|
||||
#include "node/node.h"
|
||||
#include "openglcolorprocessor.h"
|
||||
#include "openglrenderfunctions.h"
|
||||
#include "render/colormanager.h"
|
||||
#include "render/pixelformat.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
OpenGLProxy* OpenGLProxy::instance_ = nullptr;
|
||||
|
||||
OpenGLProxy::OpenGLProxy(QObject *parent) :
|
||||
QObject(parent),
|
||||
ctx_(nullptr),
|
||||
functions_(nullptr)
|
||||
{
|
||||
surface_.create();
|
||||
}
|
||||
|
||||
OpenGLProxy::~OpenGLProxy()
|
||||
{
|
||||
Close();
|
||||
|
||||
surface_.destroy();
|
||||
}
|
||||
|
||||
void OpenGLProxy::CreateInstance()
|
||||
{
|
||||
instance_ = new OpenGLProxy();
|
||||
|
||||
QThread* proxy_thread = new QThread();
|
||||
proxy_thread->start(QThread::IdlePriority);
|
||||
instance_->moveToThread(proxy_thread);
|
||||
|
||||
if (!instance_->Init()) {
|
||||
DestroyInstance();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLProxy::DestroyInstance()
|
||||
{
|
||||
if (instance_) {
|
||||
instance_->thread()->quit();
|
||||
instance_->thread()->wait();
|
||||
instance_->thread()->deleteLater();
|
||||
instance_->deleteLater();
|
||||
instance_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenGLProxy::Init()
|
||||
{
|
||||
// Create context object
|
||||
ctx_ = new QOpenGLContext();
|
||||
|
||||
// Create OpenGL context (automatically destroys any existing if there is one)
|
||||
if (!ctx_->create()) {
|
||||
qWarning() << "Failed to create OpenGL context in thread" << thread();
|
||||
return false;
|
||||
}
|
||||
|
||||
ctx_->moveToThread(this->thread());
|
||||
|
||||
// The rest of the initialization needs to occur in the other thread, so we signal for it to start
|
||||
QMetaObject::invokeMethod(this, "FinishInit", Qt::QueuedConnection);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariant OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, const VideoParams& params, const RenderMode::Mode& mode)
|
||||
{
|
||||
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(stream);
|
||||
|
||||
// Set up OCIO context
|
||||
QString colorspace_match = video_stream->get_colorspace_match_string();
|
||||
|
||||
OpenGLColorProcessorPtr color_processor = std::static_pointer_cast<OpenGLColorProcessor>(color_cache_.value(colorspace_match));
|
||||
|
||||
if (!color_processor) {
|
||||
color_processor = OpenGLColorProcessor::Create(video_stream->footage()->project()->color_manager(),
|
||||
video_stream->colorspace(),
|
||||
video_stream->footage()->project()->color_manager()->GetReferenceColorSpace());
|
||||
color_cache_.insert(colorspace_match, color_processor);
|
||||
}
|
||||
|
||||
ColorManager::OCIOMethod ocio_method = ColorManager::GetOCIOMethodForMode(mode);
|
||||
|
||||
// OCIO's CPU conversion is more accurate, so for online we render on CPU but offline we render GPU
|
||||
if (ocio_method == ColorManager::kOCIOAccurate) {
|
||||
bool has_alpha = PixelFormat::FormatHasAlphaChannel(frame->format());
|
||||
|
||||
// Convert frame to float for OCIO
|
||||
frame = PixelFormat::ConvertPixelFormat(frame,
|
||||
has_alpha
|
||||
? PixelFormat::PIX_FMT_RGBA32F
|
||||
: PixelFormat::PIX_FMT_RGB32F);
|
||||
|
||||
// If alpha is associated, disassociate for the color transform
|
||||
if (has_alpha && video_stream->premultiplied_alpha()) {
|
||||
ColorManager::DisassociateAlpha(frame);
|
||||
}
|
||||
|
||||
// Perform color transform
|
||||
color_processor->ConvertFrame(frame);
|
||||
|
||||
// Associate alpha
|
||||
if (has_alpha) {
|
||||
if (video_stream->premultiplied_alpha()) {
|
||||
ColorManager::ReassociateAlpha(frame);
|
||||
} else {
|
||||
ColorManager::AssociateAlpha(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLTextureCache::ReferencePtr footage_tex_ref = texture_cache_.Get(ctx_, frame);
|
||||
|
||||
if (ocio_method == ColorManager::kOCIOFast) {
|
||||
if (!color_processor->IsEnabled()) {
|
||||
color_processor->Enable(ctx_, video_stream->premultiplied_alpha());
|
||||
}
|
||||
|
||||
VideoParams frame_params = frame->video_params();
|
||||
|
||||
PixelFormat::Format texture_fmt;
|
||||
if (PixelFormat::FormatHasAlphaChannel(frame_params.format())) {
|
||||
texture_fmt = PixelFormat::GetFormatWithAlphaChannel(params.format());
|
||||
} else {
|
||||
texture_fmt = PixelFormat::GetFormatWithoutAlphaChannel(params.format());
|
||||
}
|
||||
|
||||
VideoParams dest_params(frame_params.width(),
|
||||
frame_params.height(),
|
||||
texture_fmt,
|
||||
frame_params.pixel_aspect_ratio(),
|
||||
frame_params.interlacing(),
|
||||
frame_params.divider());
|
||||
|
||||
// Create destination texture
|
||||
OpenGLTextureCache::ReferencePtr associated_tex_ref = texture_cache_.Get(ctx_, dest_params);
|
||||
|
||||
buffer_.Attach(associated_tex_ref->texture(), true);
|
||||
buffer_.Bind();
|
||||
footage_tex_ref->texture()->Bind();
|
||||
|
||||
// Set viewport for texture size
|
||||
functions_->glViewport(0, 0, associated_tex_ref->texture()->width(), associated_tex_ref->texture()->height());
|
||||
|
||||
// Blit old texture to new texture through OCIO shader
|
||||
color_processor->ProcessOpenGL();
|
||||
|
||||
footage_tex_ref->texture()->Release();
|
||||
buffer_.Release();
|
||||
buffer_.Detach();
|
||||
|
||||
footage_tex_ref = associated_tex_ref;
|
||||
}
|
||||
|
||||
return QVariant::fromValue(footage_tex_ref);
|
||||
}
|
||||
|
||||
QVariant OpenGLProxy::PreCachedFrameToValue(FramePtr frame)
|
||||
{
|
||||
return QVariant::fromValue(texture_cache_.Get(ctx_, frame));
|
||||
}
|
||||
|
||||
OpenGLShaderPtr OpenGLProxy::ResolveShaderFromCache(const Node *node, const QString &shader_id)
|
||||
{
|
||||
// Make a composite of the node ID and the shader ID (if applicable)
|
||||
QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), shader_id);
|
||||
OpenGLShaderPtr shader = shader_cache_.value(full_shader_id);
|
||||
|
||||
if (!shader) {
|
||||
// Since we have shader code, compile it now
|
||||
ShaderCode code = node->GetShaderCode(shader_id);
|
||||
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 = OpenGLShader::Create();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
void OpenGLProxy::Close()
|
||||
{
|
||||
shader_cache_.clear();
|
||||
buffer_.Destroy();
|
||||
copy_pipeline_ = nullptr;
|
||||
functions_ = nullptr;
|
||||
delete ctx_;
|
||||
ctx_ = nullptr;
|
||||
}
|
||||
|
||||
QVariant OpenGLProxy::RunNodeAccelerated(const Node *node,
|
||||
const TimeRange &range,
|
||||
const ShaderJob &job,
|
||||
const VideoParams& 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;
|
||||
|
||||
OpenGLShaderPtr shader = ResolveShaderFromCache(node, job.GetShaderID());
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void OpenGLProxy::TextureToBuffer(const QVariant& tex_in,
|
||||
FramePtr frame,
|
||||
const QMatrix4x4& matrix)
|
||||
{
|
||||
OpenGLTextureCache::ReferencePtr texture = tex_in.value<OpenGLTextureCache::ReferencePtr>();
|
||||
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
OpenGLTextureCache::ReferencePtr download_tex;
|
||||
|
||||
if (!frame->is_allocated()) {
|
||||
// If the frame isn't allocated, we'll assume that we're allocating it to the texture dimensions
|
||||
frame->set_video_params(texture->texture()->params());
|
||||
frame->allocate();
|
||||
}
|
||||
|
||||
functions_->glViewport(0, 0, frame->width(), frame->height());
|
||||
|
||||
if (frame->width() != texture->texture()->width()
|
||||
|| frame->height() != texture->texture()->height()) {
|
||||
|
||||
// Resize the texture if necessary
|
||||
OpenGLTextureCache::ReferencePtr resized = texture_cache_.Get(ctx_, frame->video_params());
|
||||
|
||||
buffer_.Attach(resized->texture(), true);
|
||||
buffer_.Bind();
|
||||
|
||||
texture->texture()->Bind();
|
||||
|
||||
// Blit to this new texture
|
||||
OpenGLRenderFunctions::Blit(copy_pipeline_, false, matrix);
|
||||
|
||||
texture->texture()->Release();
|
||||
|
||||
buffer_.Release();
|
||||
buffer_.Detach();
|
||||
|
||||
download_tex = resized;
|
||||
|
||||
} else {
|
||||
|
||||
download_tex = texture;
|
||||
|
||||
}
|
||||
|
||||
buffer_.Attach(download_tex->texture());
|
||||
buffer_.Bind();
|
||||
|
||||
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, frame->linesize_pixels());
|
||||
|
||||
functions_->glReadPixels(0,
|
||||
0,
|
||||
frame->width(),
|
||||
frame->height(),
|
||||
OpenGLRenderFunctions::GetPixelFormat(frame->format()),
|
||||
OpenGLRenderFunctions::GetPixelType(frame->format()),
|
||||
frame->data());
|
||||
|
||||
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||
|
||||
buffer_.Release();
|
||||
buffer_.Detach();
|
||||
}
|
||||
|
||||
void OpenGLProxy::FinishInit()
|
||||
{
|
||||
// Make context current on that surface
|
||||
if (!ctx_->makeCurrent(&surface_)) {
|
||||
qWarning() << "Failed to makeCurrent() on offscreen surface in thread" << thread();
|
||||
return;
|
||||
}
|
||||
|
||||
// Store OpenGL functions instance
|
||||
functions_ = ctx_->functions();
|
||||
functions_->glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
buffer_.Create(ctx_);
|
||||
|
||||
copy_pipeline_ = OpenGLShader::CreateDefault();
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -1,122 +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 OPENGLPROXY_H
|
||||
#define OPENGLPROXY_H
|
||||
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLContext>
|
||||
|
||||
#include "common/timerange.h"
|
||||
#include "node/value.h"
|
||||
#include "openglcolorprocessor.h"
|
||||
#include "openglframebuffer.h"
|
||||
#include "opengltexturecache.h"
|
||||
#include "render/shaderinfo.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class OpenGLProxy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OpenGLProxy(QObject* parent = nullptr);
|
||||
|
||||
virtual ~OpenGLProxy() override;
|
||||
|
||||
static void CreateInstance();
|
||||
|
||||
static void DestroyInstance();
|
||||
|
||||
static OpenGLProxy* instance()
|
||||
{
|
||||
return instance_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize OpenGL instance in whatever thread this object is a part of
|
||||
*
|
||||
* This function creates a context (shared with share_ctx provided in the constructor) as well as various other
|
||||
* OpenGL thread-specific objects necessary for rendering. This function should only ever be called from the main
|
||||
* thread (i.e. the thread where share_ctx is current on) but AFTER this object has been pushed to its thread with
|
||||
* moveToThread(). If this function is called from a different thread, it could fail or even segfault on some
|
||||
* platforms.
|
||||
*
|
||||
* The reason this function must be called in the main thread (rather than initializing asynchronously in a separate
|
||||
* thread) is because different platforms have different rules about creating a share context with a context that
|
||||
* is still "current" in another thread. While some implementations do allow this, Windows OpenGL (wgl) explicitly
|
||||
* forbids it and other platforms/drivers will segfault attempting it. While we can obviously call "doneCurrent", I
|
||||
* haven't found any reliable way to prevent the main thread from making it current again before initialization is
|
||||
* complete other than blocking it entirely.
|
||||
*
|
||||
* To get around this, we create all share contexts in the main thread and then move them to the other thread
|
||||
* afterwards (which is completely legal). While annoying, this gets around the issue listed above by both preventing
|
||||
* the main thread from using the context during initialization and preventing more than one shared context being made
|
||||
* at the same time (which may or may not actually make a difference).
|
||||
*/
|
||||
bool Init();
|
||||
|
||||
void Close();
|
||||
|
||||
public slots:
|
||||
QVariant RunNodeAccelerated(const OLIVE_NAMESPACE::Node *node,
|
||||
const OLIVE_NAMESPACE::TimeRange &range,
|
||||
const OLIVE_NAMESPACE::ShaderJob &job,
|
||||
const OLIVE_NAMESPACE::VideoParams ¶ms);
|
||||
|
||||
void TextureToBuffer(const QVariant& texture,
|
||||
OLIVE_NAMESPACE::FramePtr frame,
|
||||
const QMatrix4x4& matrix);
|
||||
|
||||
QVariant FrameToValue(OLIVE_NAMESPACE::FramePtr frame,
|
||||
OLIVE_NAMESPACE::StreamPtr stream,
|
||||
const OLIVE_NAMESPACE::VideoParams ¶ms,
|
||||
const OLIVE_NAMESPACE::RenderMode::Mode &mode);
|
||||
|
||||
QVariant PreCachedFrameToValue(OLIVE_NAMESPACE::FramePtr frame);
|
||||
|
||||
private:
|
||||
OpenGLShaderPtr ResolveShaderFromCache(const Node* node, const QString &shader_id);
|
||||
|
||||
QOpenGLContext* ctx_;
|
||||
QOffscreenSurface surface_;
|
||||
|
||||
QOpenGLFunctions* functions_;
|
||||
|
||||
OpenGLFramebuffer buffer_;
|
||||
|
||||
OpenGLColorProcessorCache color_cache_;
|
||||
|
||||
OpenGLShaderPtr copy_pipeline_;
|
||||
|
||||
QHash<QString, OpenGLShaderPtr> shader_cache_;
|
||||
|
||||
OpenGLTextureCache texture_cache_;
|
||||
|
||||
static OpenGLProxy* instance_;
|
||||
|
||||
private slots:
|
||||
void FinishInit();
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // OPENGLPROXY_H
|
||||
@@ -1,232 +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 "openglrenderfunctions.h"
|
||||
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
#include <QOpenGLBuffer>
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
const QVector<GLfloat> blit_vertices = {
|
||||
-1.0f, -1.0f, 0.0f,
|
||||
1.0f, -1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f,
|
||||
|
||||
-1.0f, -1.0f, 0.0f,
|
||||
-1.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f
|
||||
};
|
||||
|
||||
const QVector<GLfloat> blit_texcoords = {
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f
|
||||
};
|
||||
|
||||
const QVector<GLfloat> flipped_blit_texcoords = {
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Set up texture parameters and mipmap for drawing
|
||||
*
|
||||
* Internal function used just before drawing to allow mipmapped bilinear filtering when drawing textures small.
|
||||
*
|
||||
* @param f
|
||||
*
|
||||
* Currently active QOpenGLFunctions object (use context()->functions() if unsure).
|
||||
*/
|
||||
void OpenGLRenderFunctions::PrepareToDraw(QOpenGLFunctions* f)
|
||||
{
|
||||
f->glGenerateMipmap(GL_TEXTURE_2D);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
GLint OpenGLRenderFunctions::GetInternalFormat(const 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 OpenGLRenderFunctions::GetPixelFormat(const PixelFormat::Format &format)
|
||||
{
|
||||
if (PixelFormat::FormatHasAlphaChannel(format)) {
|
||||
return GL_RGBA;
|
||||
} else {
|
||||
return GL_RGB;
|
||||
}
|
||||
}
|
||||
|
||||
GLenum OpenGLRenderFunctions::GetPixelType(const 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;
|
||||
}
|
||||
|
||||
void OpenGLRenderFunctions::Blit(OpenGLShaderPtr pipeline, bool flipped, QMatrix4x4 matrix)
|
||||
{
|
||||
Blit(pipeline.get(), flipped, matrix);
|
||||
}
|
||||
|
||||
void OpenGLRenderFunctions::Blit(OpenGLShader *pipeline, bool flipped, QMatrix4x4 matrix)
|
||||
{
|
||||
Blit(pipeline,
|
||||
GL_TRIANGLES,
|
||||
blit_vertices,
|
||||
flipped ? flipped_blit_texcoords : blit_texcoords,
|
||||
matrix);
|
||||
}
|
||||
|
||||
void OpenGLRenderFunctions::Blit(OpenGLShader *pipeline, GLenum mode, const QVector<GLfloat> &vert, const QVector<GLfloat> &tex, QMatrix4x4 matrix)
|
||||
{
|
||||
QOpenGLFunctions* func = QOpenGLContext::currentContext()->functions();
|
||||
|
||||
PrepareToDraw(func);
|
||||
|
||||
QOpenGLVertexArrayObject m_vao;
|
||||
m_vao.create();
|
||||
m_vao.bind();
|
||||
|
||||
QOpenGLBuffer m_vbo;
|
||||
m_vbo.create();
|
||||
m_vbo.bind();
|
||||
m_vbo.allocate(vert.constData(), vert.size() * sizeof(GLfloat));
|
||||
m_vbo.release();
|
||||
|
||||
QOpenGLBuffer m_vbo2;
|
||||
m_vbo2.create();
|
||||
m_vbo2.bind();
|
||||
m_vbo2.allocate(tex.constData(), tex.size() * sizeof(GLfloat));
|
||||
m_vbo2.release();
|
||||
|
||||
pipeline->bind();
|
||||
|
||||
pipeline->setUniformValue("ove_mvpmat", matrix);
|
||||
pipeline->setUniformValue("ove_maintex", 0);
|
||||
|
||||
int vertex_location = pipeline->attributeLocation("a_position");
|
||||
m_vbo.bind();
|
||||
func->glEnableVertexAttribArray(vertex_location);
|
||||
func->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
|
||||
m_vbo.release();
|
||||
|
||||
int tex_location = pipeline->attributeLocation("a_texcoord");
|
||||
m_vbo2.bind();
|
||||
func->glEnableVertexAttribArray(tex_location);
|
||||
func->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
|
||||
m_vbo2.release();
|
||||
|
||||
// (Size / 3) because we assume each GLfloat has an XYZ pair
|
||||
func->glDrawArrays(mode, 0, blit_vertices.size() / 3);
|
||||
|
||||
pipeline->release();
|
||||
|
||||
m_vbo2.destroy();
|
||||
m_vbo.destroy();
|
||||
m_vao.release();
|
||||
m_vao.destroy();
|
||||
}
|
||||
|
||||
void OpenGLRenderFunctions::OCIOBlit(OpenGLShaderPtr pipeline, GLuint lut, bool flipped, QMatrix4x4 matrix)
|
||||
{
|
||||
OCIOBlit(pipeline.get(), lut, flipped, matrix);
|
||||
}
|
||||
|
||||
void OpenGLRenderFunctions::OCIOBlit(OpenGLShader *pipeline,
|
||||
GLuint lut,
|
||||
bool flipped,
|
||||
QMatrix4x4 matrix)
|
||||
{
|
||||
QOpenGLContext* ctx = QOpenGLContext::currentContext();
|
||||
QOpenGLExtraFunctions* xf = ctx->extraFunctions();
|
||||
|
||||
xf->glActiveTexture(GL_TEXTURE1);
|
||||
xf->glBindTexture(GL_TEXTURE_3D, lut);
|
||||
xf->glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
pipeline->bind();
|
||||
|
||||
pipeline->setUniformValue("ove_ociolut", 1);
|
||||
|
||||
Blit(pipeline, flipped, matrix);
|
||||
|
||||
pipeline->release();
|
||||
|
||||
xf->glActiveTexture(GL_TEXTURE1);
|
||||
xf->glBindTexture(GL_TEXTURE_3D, 0);
|
||||
xf->glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -1,70 +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 OPENGLFUNCTIONS_H
|
||||
#define OPENGLFUNCTIONS_H
|
||||
|
||||
#include <QMatrix4x4>
|
||||
#include <QMutex>
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
#include "openglshader.h"
|
||||
#include "render/pixelformat.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class OpenGLRenderFunctions {
|
||||
public:
|
||||
/**
|
||||
* @brief Draw texture on screen
|
||||
*
|
||||
* @param pipeline
|
||||
*
|
||||
* Shader to use for the texture drawing
|
||||
*
|
||||
* @param flipped
|
||||
*
|
||||
* Draw the texture vertically flipped (defaults to FALSE)
|
||||
*
|
||||
* @param matrix
|
||||
*
|
||||
* Transformation matrix to use when drawing (defaults to no transform)
|
||||
*/
|
||||
static void Blit(OpenGLShaderPtr pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4());
|
||||
static void Blit(OpenGLShader* pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4());
|
||||
static void Blit(OpenGLShader* pipeline, GLenum mode, const QVector<GLfloat>& vert,
|
||||
const QVector<GLfloat>& tex, QMatrix4x4 matrix = QMatrix4x4());
|
||||
|
||||
static void OCIOBlit(OpenGLShaderPtr pipeline, GLuint lut, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4());
|
||||
static void OCIOBlit(OpenGLShader* pipeline, GLuint lut, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4());
|
||||
|
||||
static void PrepareToDraw(QOpenGLFunctions* f);
|
||||
|
||||
static GLint GetInternalFormat(const PixelFormat::Format& format);
|
||||
|
||||
static GLenum GetPixelFormat(const PixelFormat::Format& format);
|
||||
|
||||
static GLenum GetPixelType(const PixelFormat::Format& format);
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // OPENGLFUNCTIONS_H
|
||||
@@ -1,254 +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 "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
|
||||
@@ -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 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,191 +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 "opengltexture.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QtMath>
|
||||
|
||||
#include "openglrenderfunctions.h"
|
||||
#include "render/pixelformat.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
OpenGLTexture::OpenGLTexture() :
|
||||
created_ctx_(nullptr),
|
||||
texture_(0)
|
||||
{
|
||||
}
|
||||
|
||||
OpenGLTexture::~OpenGLTexture()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool OpenGLTexture::IsCreated() const
|
||||
{
|
||||
return (texture_);
|
||||
}
|
||||
|
||||
void OpenGLTexture::Create(QOpenGLContext *ctx, const VideoParams ¶ms, const void* data, int linesize)
|
||||
{
|
||||
if (!ctx) {
|
||||
qWarning() << "OpenGLTexture::Create was passed an invalid context";
|
||||
return;
|
||||
}
|
||||
|
||||
Destroy();
|
||||
|
||||
created_ctx_ = ctx;
|
||||
params_ = params;
|
||||
|
||||
connect(created_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()), Qt::DirectConnection);
|
||||
|
||||
// Create main texture
|
||||
CreateInternal(created_ctx_, &texture_, data, linesize);
|
||||
}
|
||||
|
||||
void OpenGLTexture::Create(QOpenGLContext *ctx, const VideoParams ¶ms)
|
||||
{
|
||||
Create(ctx, params, nullptr, 0);
|
||||
}
|
||||
|
||||
void OpenGLTexture::Create(QOpenGLContext *ctx, FramePtr frame)
|
||||
{
|
||||
Create(ctx, frame.get());
|
||||
}
|
||||
|
||||
void OpenGLTexture::Create(QOpenGLContext *ctx, Frame *frame)
|
||||
{
|
||||
Create(ctx, frame->video_params(), frame->data(), frame->linesize_pixels());
|
||||
}
|
||||
|
||||
void OpenGLTexture::Destroy()
|
||||
{
|
||||
if (created_ctx_) {
|
||||
disconnect(created_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()));
|
||||
|
||||
created_ctx_->functions()->glDeleteTextures(1, &texture_);
|
||||
texture_ = 0;
|
||||
|
||||
created_ctx_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLTexture::Bind()
|
||||
{
|
||||
created_ctx_->functions()->glBindTexture(GL_TEXTURE_2D, texture_);
|
||||
}
|
||||
|
||||
void OpenGLTexture::Release()
|
||||
{
|
||||
created_ctx_->functions()->glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void OpenGLTexture::SetPixelAspectRatio(const rational &r)
|
||||
{
|
||||
params_ = VideoParams(params_.width(),
|
||||
params_.height(),
|
||||
params_.time_base(),
|
||||
params_.format(),
|
||||
r,
|
||||
params_.interlacing(),
|
||||
params_.divider());
|
||||
}
|
||||
|
||||
void OpenGLTexture::Upload(FramePtr frame)
|
||||
{
|
||||
Upload(frame.get());
|
||||
}
|
||||
|
||||
void OpenGLTexture::Upload(Frame *frame)
|
||||
{
|
||||
Upload(frame->data(), frame->linesize_pixels());
|
||||
}
|
||||
|
||||
void OpenGLTexture::Upload(const void *data, int linesize)
|
||||
{
|
||||
if (!IsCreated()) {
|
||||
qWarning() << "OpenGLTexture::Upload() called while it wasn't created";
|
||||
return;
|
||||
}
|
||||
|
||||
Bind();
|
||||
|
||||
created_ctx_->functions()->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
||||
|
||||
created_ctx_->functions()->glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
width(),
|
||||
height(),
|
||||
OpenGLRenderFunctions::GetPixelFormat(format()),
|
||||
OpenGLRenderFunctions::GetPixelType(format()),
|
||||
data);
|
||||
|
||||
created_ctx_->functions()->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
Release();
|
||||
}
|
||||
|
||||
void OpenGLTexture::CreateInternal(QOpenGLContext* create_ctx, GLuint* tex, const void *data, int linesize)
|
||||
{
|
||||
QOpenGLFunctions* f = create_ctx->functions();
|
||||
|
||||
// Create texture
|
||||
f->glGenTextures(1, tex);
|
||||
|
||||
// Verify texture
|
||||
if (texture_ == 0) {
|
||||
qWarning() << "OpenGL texture creation failed";
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind texture
|
||||
f->glBindTexture(GL_TEXTURE_2D, *tex);
|
||||
|
||||
// Set linesize
|
||||
f->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
||||
|
||||
// Allocate storage for texture
|
||||
f->glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
OpenGLRenderFunctions::GetInternalFormat(format()),
|
||||
width(),
|
||||
height(),
|
||||
0,
|
||||
OpenGLRenderFunctions::GetPixelFormat(format()),
|
||||
OpenGLRenderFunctions::GetPixelType(format()),
|
||||
data);
|
||||
|
||||
// Return linesize to default
|
||||
f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
// Set texture filtering to bilinear
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Release texture
|
||||
f->glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -1,118 +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 OPENGLTEXTURE_H
|
||||
#define OPENGLTEXTURE_H
|
||||
|
||||
#include <memory>
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
#include "codec/frame.h"
|
||||
#include "render/pixelformat.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
/**
|
||||
* @brief A class wrapper around an OpenGL texture
|
||||
*/
|
||||
class OpenGLTexture : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OpenGLTexture();
|
||||
virtual ~OpenGLTexture() override;
|
||||
|
||||
DISABLE_COPY_MOVE(OpenGLTexture)
|
||||
|
||||
void Create(QOpenGLContext* ctx, const VideoParams& params, const void *data, int linesize);
|
||||
void Create(QOpenGLContext* ctx, const VideoParams& params);
|
||||
void Create(QOpenGLContext* ctx, FramePtr frame);
|
||||
void Create(QOpenGLContext* ctx, Frame* frame);
|
||||
|
||||
bool IsCreated() const;
|
||||
|
||||
void Bind();
|
||||
|
||||
void Release();
|
||||
|
||||
const VideoParams& params() const
|
||||
{
|
||||
return params_;
|
||||
}
|
||||
|
||||
const int& width() const
|
||||
{
|
||||
return params_.effective_width();
|
||||
}
|
||||
|
||||
const int& height() const
|
||||
{
|
||||
return params_.effective_height();
|
||||
}
|
||||
|
||||
const PixelFormat::Format &format() const
|
||||
{
|
||||
return params_.format();
|
||||
}
|
||||
|
||||
const GLuint& texture() const
|
||||
{
|
||||
return texture_;
|
||||
}
|
||||
|
||||
const int& divider() const
|
||||
{
|
||||
return params_.divider();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Changes the pixel aspect ratio metadata of this textuer
|
||||
*
|
||||
* This metadata is important for our render pipeline, but we don't need to do any re-allocation
|
||||
* to set it like we do with other VideoParam changes, so we provide a function to change only
|
||||
* the PAR here.
|
||||
*/
|
||||
void SetPixelAspectRatio(const rational& r);
|
||||
|
||||
void Upload(FramePtr frame);
|
||||
void Upload(Frame* frame);
|
||||
void Upload(const void *data, int linesize);
|
||||
|
||||
public slots:
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
void CreateInternal(QOpenGLContext *create_ctx, GLuint *tex, const void *data, int linesize);
|
||||
|
||||
QOpenGLContext* created_ctx_;
|
||||
|
||||
GLuint texture_;
|
||||
|
||||
VideoParams params_;
|
||||
|
||||
};
|
||||
|
||||
using OpenGLTexturePtr = std::shared_ptr<OpenGLTexture>;
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::OpenGLTexturePtr)
|
||||
|
||||
#endif // OPENGLTEXTURE_H
|
||||
@@ -1,121 +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 "opengltexturecache.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
OpenGLTextureCache::~OpenGLTextureCache()
|
||||
{
|
||||
foreach (Reference* ref, existing_references_) {
|
||||
ref->ParentKilled();
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, FramePtr frame)
|
||||
{
|
||||
return Get(ctx, frame.get());
|
||||
}
|
||||
|
||||
OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, Frame *frame)
|
||||
{
|
||||
return Get(ctx, frame->video_params(), frame->data(), frame->linesize_pixels());
|
||||
}
|
||||
|
||||
OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext* ctx, const VideoParams ¶ms, const void *data, int linesize)
|
||||
{
|
||||
OpenGLTexturePtr texture = nullptr;
|
||||
|
||||
lock_.lock();
|
||||
|
||||
// Iterate through textures and see if we have one that matches these parameters
|
||||
for (int i=0;i<available_textures_.size();i++) {
|
||||
OpenGLTexturePtr test = available_textures_.at(i);
|
||||
|
||||
if (test->width() == params.effective_width()
|
||||
&& test->height() == params.effective_height()
|
||||
&& test->format() == params.format()) {
|
||||
texture = test;
|
||||
available_textures_.removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find a texture, we'll need to create one
|
||||
if (!texture) {
|
||||
texture = std::make_shared<OpenGLTexture>();
|
||||
texture->Create(ctx, params);
|
||||
}
|
||||
|
||||
texture->SetPixelAspectRatio(params.pixel_aspect_ratio());
|
||||
|
||||
ReferencePtr ref = std::make_shared<Reference>(this, texture);
|
||||
existing_references_.append(ref.get());
|
||||
|
||||
lock_.unlock();
|
||||
|
||||
if (data) {
|
||||
texture->Upload(data, linesize);
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, const VideoParams ¶ms)
|
||||
{
|
||||
return Get(ctx, params, nullptr, 0);
|
||||
}
|
||||
|
||||
void OpenGLTextureCache::Relinquish(OpenGLTextureCache::Reference *ref)
|
||||
{
|
||||
OpenGLTexturePtr tex = ref->texture();
|
||||
|
||||
lock_.lock();
|
||||
|
||||
existing_references_.removeOne(ref);
|
||||
available_textures_.append(tex);
|
||||
|
||||
lock_.unlock();
|
||||
}
|
||||
|
||||
OpenGLTextureCache::Reference::Reference(OpenGLTextureCache *parent, OpenGLTexturePtr texture) :
|
||||
parent_(parent),
|
||||
texture_(texture)
|
||||
{
|
||||
}
|
||||
|
||||
OpenGLTextureCache::Reference::~Reference()
|
||||
{
|
||||
if (parent_) {
|
||||
parent_->Relinquish(this);
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLTexturePtr OpenGLTextureCache::Reference::texture()
|
||||
{
|
||||
return texture_;
|
||||
}
|
||||
|
||||
void OpenGLTextureCache::Reference::ParentKilled()
|
||||
{
|
||||
parent_ = nullptr;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -1,80 +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 OPENGLTEXTURECACHE_H
|
||||
#define OPENGLTEXTURECACHE_H
|
||||
|
||||
#include <QMutex>
|
||||
|
||||
#include "openglframebuffer.h"
|
||||
#include "opengltexture.h"
|
||||
#include "render/videoparams.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class OpenGLTextureCache
|
||||
{
|
||||
public:
|
||||
class Reference {
|
||||
public:
|
||||
Reference(OpenGLTextureCache* parent, OpenGLTexturePtr texture);
|
||||
~Reference();
|
||||
|
||||
DISABLE_COPY_MOVE(Reference)
|
||||
|
||||
OpenGLTexturePtr texture();
|
||||
|
||||
void ParentKilled();
|
||||
|
||||
private:
|
||||
OpenGLTextureCache* parent_;
|
||||
|
||||
OpenGLTexturePtr texture_;
|
||||
};
|
||||
|
||||
using ReferencePtr = std::shared_ptr<Reference>;
|
||||
|
||||
OpenGLTextureCache() = default;
|
||||
|
||||
~OpenGLTextureCache();
|
||||
|
||||
DISABLE_COPY_MOVE(OpenGLTextureCache)
|
||||
|
||||
ReferencePtr Get(QOpenGLContext *ctx, FramePtr frame);
|
||||
ReferencePtr Get(QOpenGLContext *ctx, Frame* frame);
|
||||
ReferencePtr Get(QOpenGLContext *ctx, const VideoParams& params, const void *data, int linesize);
|
||||
ReferencePtr Get(QOpenGLContext *ctx, const VideoParams& params);
|
||||
|
||||
private:
|
||||
void Relinquish(Reference* ref);
|
||||
|
||||
QMutex lock_;
|
||||
|
||||
QList<OpenGLTexturePtr> available_textures_;
|
||||
|
||||
QList<Reference*> existing_references_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::OpenGLTextureCache::ReferencePtr)
|
||||
|
||||
#endif // OPENGLTEXTURECACHE_H
|
||||
@@ -1,6 +1,36 @@
|
||||
/***
|
||||
|
||||
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 "rendercontext.h"
|
||||
|
||||
RenderContext::RenderContext()
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
RenderContext::RenderContext(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QVariant RenderContext::CreateTexture(const VideoParams ¶m)
|
||||
{
|
||||
return CreateTexture(param, nullptr, 0);
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -1,11 +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 RENDERCONTEXT_H
|
||||
#define RENDERCONTEXT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
|
||||
class RenderContext
|
||||
#include "common/define.h"
|
||||
#include "render/videoparams.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class RenderContext : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RenderContext();
|
||||
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
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/***
|
||||
|
||||
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 "rendercontextthreadwrapper.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
RenderContextThreadWrapper::RenderContextThreadWrapper(RenderContext *inner, QObject *parent) :
|
||||
RenderContext(parent),
|
||||
inner_(inner),
|
||||
thread_(nullptr)
|
||||
{
|
||||
inner_->setParent(this);
|
||||
}
|
||||
|
||||
bool RenderContextThreadWrapper::Init()
|
||||
{
|
||||
// Create thread
|
||||
QThread* thread = new QThread(this);
|
||||
thread->start(QThread::IdlePriority);
|
||||
|
||||
// Move context to thread
|
||||
inner_->moveToThread(thread);
|
||||
|
||||
// Init context in main thread
|
||||
inner_->Init();
|
||||
|
||||
// Queue post-init in new thread
|
||||
QMetaObject::invokeMethod(inner_, "PostInit", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void RenderContextThreadWrapper::Destroy()
|
||||
{
|
||||
if (thread_) {
|
||||
QMetaObject::invokeMethod(inner_, "Destroy", Qt::QueuedConnection);
|
||||
|
||||
thread_->quit();
|
||||
thread_->wait();
|
||||
delete thread_;
|
||||
thread_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
QVariant RenderContextThreadWrapper::CreateTexture(const VideoParams ¶m, void *data, int linesize)
|
||||
{
|
||||
QVariant v;
|
||||
|
||||
QMetaObject::invokeMethod(inner_, "CreateTexture", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVariant, v),
|
||||
OLIVE_NS_CONST_ARG(VideoParams&, param),
|
||||
Q_ARG(void*, data),
|
||||
Q_ARG(int, linesize));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void RenderContextThreadWrapper::DestroyTexture(QVariant texture)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "DestroyTexture", Qt::QueuedConnection,
|
||||
Q_ARG(QVariant, texture));
|
||||
}
|
||||
|
||||
void RenderContextThreadWrapper::UploadToTexture(QVariant texture, void *data, int linesize)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "UploadToTexture", Qt::QueuedConnection,
|
||||
Q_ARG(QVariant, texture),
|
||||
Q_ARG(void*, data),
|
||||
Q_ARG(int, linesize));
|
||||
}
|
||||
|
||||
void RenderContextThreadWrapper::DownloadFromTexture(QVariant texture, void *data, int linesize)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "DownloadFromTexture", Qt::QueuedConnection,
|
||||
Q_ARG(QVariant, texture),
|
||||
Q_ARG(void*, data),
|
||||
Q_ARG(int, linesize));
|
||||
}
|
||||
|
||||
VideoParams RenderContextThreadWrapper::GetParamsFromTexture(QVariant texture)
|
||||
{
|
||||
VideoParams p;
|
||||
|
||||
QMetaObject::invokeMethod(inner_, "GetParamsFromTexture", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(VideoParams, p),
|
||||
Q_ARG(QVariant, texture));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -0,0 +1,66 @@
|
||||
/***
|
||||
|
||||
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 RENDERCONTEXTTHREADWRAPPER_H
|
||||
#define RENDERCONTEXTTHREADWRAPPER_H
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#include "rendercontext.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class RenderContextThreadWrapper : public RenderContext
|
||||
{
|
||||
public:
|
||||
RenderContextThreadWrapper(RenderContext* inner, QObject* parent = nullptr);
|
||||
|
||||
virtual ~RenderContextThreadWrapper() override
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
virtual bool Init() override;
|
||||
|
||||
public slots:
|
||||
virtual void PostInit() override{}
|
||||
|
||||
virtual void Destroy() override;
|
||||
|
||||
virtual QVariant CreateTexture(const VideoParams& param, void* data, int linesize) override;
|
||||
|
||||
virtual void DestroyTexture(QVariant texture) override;
|
||||
|
||||
virtual void UploadToTexture(QVariant texture, void* data, int linesize) override;
|
||||
|
||||
virtual void DownloadFromTexture(QVariant texture, void* data, int linesize) override;
|
||||
|
||||
virtual VideoParams GetParamsFromTexture(QVariant texture) override;
|
||||
|
||||
private:
|
||||
RenderContext* inner_;
|
||||
|
||||
QThread* thread_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // RENDERCONTEXTTHREADWRAPPER_H
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "renderframebuffer.h"
|
||||
|
||||
RenderFrameBuffer::RenderFrameBuffer()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef RENDERFRAMEBUFFER_H
|
||||
#define RENDERFRAMEBUFFER_H
|
||||
|
||||
|
||||
class RenderFrameBuffer
|
||||
{
|
||||
public:
|
||||
RenderFrameBuffer();
|
||||
};
|
||||
|
||||
#endif // RENDERFRAMEBUFFER_H
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "rendershader.h"
|
||||
|
||||
RenderShader::RenderShader()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef RENDERSHADER_H
|
||||
#define RENDERSHADER_H
|
||||
|
||||
|
||||
class RenderShader
|
||||
{
|
||||
public:
|
||||
RenderShader();
|
||||
};
|
||||
|
||||
#endif // RENDERSHADER_H
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "rendertexture.h"
|
||||
|
||||
RenderTexture::RenderTexture(RenderContext *ctx)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef RENDERTEXTURE_H
|
||||
#define RENDERTEXTURE_H
|
||||
|
||||
#include "rendercontext.h"
|
||||
|
||||
class RenderTexture
|
||||
{
|
||||
public:
|
||||
RenderTexture(RenderContext* ctx);
|
||||
};
|
||||
|
||||
#endif // RENDERTEXTURE_H
|
||||
Reference in New Issue
Block a user