finished upgrade to ocio v2

This commit is contained in:
itsmattkc
2020-11-12 15:36:29 +11:00
parent ddbca1ba51
commit 8776bb9c4a
40 changed files with 1095 additions and 591 deletions
-26
View File
@@ -1,26 +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/>.
add_subdirectory(opengl)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
render/backend/renderer.cpp
render/backend/renderer.h
render/backend/rendererthreadwrapper.cpp
render/backend/rendererthreadwrapper.h
PARENT_SCOPE
)
-22
View File
@@ -1,22 +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/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
render/backend/opengl/openglrenderer.cpp
render/backend/opengl/openglrenderer.h
PARENT_SCOPE
)
@@ -1,573 +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 "openglrenderer.h"
#include <QDebug>
#include <QFloat16>
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
};
OpenGLRenderer::OpenGLRenderer(QObject* parent) :
Renderer(parent),
context_(nullptr)
{
}
OpenGLRenderer::~OpenGLRenderer()
{
Destroy();
}
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_->parent() == this && !context_->makeCurrent(&surface_)) {
qCritical() << "Failed to makeCurrent() on offscreen surface in thread" << thread();
return;
}
functions_ = context_->functions();
// Store OpenGL functions instance
functions_->glBlendFunc(GL_ONE, GL_ZERO);
// Set up framebuffer used for various things
functions_->glGenFramebuffers(1, &framebuffer_);
}
void OpenGLRenderer::Destroy()
{
if (context_) {
// Delete framebuffer
functions_->glDeleteFramebuffers(1, &framebuffer_);
// Delete context if it belongs to us
if (context_->parent() == this) {
delete context_;
}
context_ = nullptr;
// Destroy surface if we created it
if (surface_.isValid()) {
surface_.destroy();
}
}
}
void OpenGLRenderer::ClearDestination(double r, double g, double b, double a)
{
functions_->glClearColor(r, g, b, a);
functions_->glClear(GL_COLOR_BUFFER_BIT);
}
void OpenGLRenderer::AttachTextureAsDestination(Renderer::Texture* texture)
{
functions_->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
functions_->glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
texture->id().value<GLuint>(),
0);
}
void OpenGLRenderer::DetachTextureAsDestination()
{
functions_->glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
QVariant OpenGLRenderer::CreateNativeTexture(VideoParams p, void *data, int linesize)
{
GLuint texture;
functions_->glGenTextures(1, &texture);
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
GLint current_tex;
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_tex);
functions_->glBindTexture(GL_TEXTURE_2D, texture);
functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(p.format()),
p.effective_width(), p.effective_height(), 0, GL_RGBA,
GetPixelType(p.format()), data);
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
return texture;
}
void OpenGLRenderer::DestroyNativeTexture(QVariant texture)
{
GLuint t = texture.value<GLuint>();
functions_->glDeleteTextures(1, &t);
}
QVariant OpenGLRenderer::CreateNativeShader(ShaderCode code)
{
QOpenGLShaderProgram* program = new QOpenGLShaderProgram(context_);
if (!program->addShaderFromSourceCode(QOpenGLShader::Vertex, code.vert_code())) {
qCritical() << "Failed to add vertex code to shader";
goto error;
}
if (!program->addShaderFromSourceCode(QOpenGLShader::Fragment, code.frag_code())) {
qCritical() << "Failed to add fragment code to shader";
goto error;
}
if (!program->link()) {
qCritical() << "Failed to link shader";
goto error;
}
return Node::PtrToValue(program);
error:
delete program;
return QVariant();
}
void OpenGLRenderer::DestroyNativeShader(QVariant shader)
{
delete Node::ValueToPtr<QOpenGLShaderProgram>(shader);
}
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, &current_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(),
GL_RGBA, 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)
{
const VideoParams& p = texture->params();
GLint current_tex;
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_tex);
AttachTextureAsDestination(texture);
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, linesize);
functions_->glReadPixels(0,
0,
p.width(),
p.height(),
GL_RGBA,
GetPixelType(p.format()),
data);
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, 0);
DetachTextureAsDestination();
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
}
void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destination, VideoParams destination_params)
{
// If this node is iterative, we'll pick up which input here
GLuint iterative_input = 0;
QList<GLuint> textures_to_bind;
bool input_textures_have_alpha = false;
QOpenGLShaderProgram* shader = Node::ValueToPtr<QOpenGLShaderProgram>(s);
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;
}
// This variable is used in the shader, let's set it
const ShaderValue& value = it.value();
if (value.array) {
qWarning() << "FIXME: Array support is currently a stub";
}
switch (value.type) {
case NodeInput::kInt:
// kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to
// over/underflows if the number is large enough, but the likelihood of that is quite low.
shader->setUniformValue(variable_location, value.data.toInt());
break;
case NodeInput::kFloat:
// kFloat technically specifies a double but as above, OpenGL doesn't support those.
shader->setUniformValue(variable_location, value.data.toFloat());
break;
case NodeInput::kVec2:
shader->setUniformValue(variable_location, value.data.value<QVector2D>());
break;
case NodeInput::kVec3:
shader->setUniformValue(variable_location, value.data.value<QVector3D>());
break;
case NodeInput::kVec4:
shader->setUniformValue(variable_location, value.data.value<QVector4D>());
break;
case NodeInput::kMatrix:
shader->setUniformValue(variable_location, value.data.value<QMatrix4x4>());
break;
case NodeInput::kCombo:
shader->setUniformValue(variable_location, value.data.value<int>());
break;
case NodeInput::kColor:
{
Color color = value.data.value<Color>();
shader->setUniformValue(variable_location,
color.red(), color.green(), color.blue(), color.alpha());
break;
}
case NodeInput::kBoolean:
shader->setUniformValue(variable_location, value.data.toBool());
break;
case NodeInput::kBuffer:
case NodeInput::kTexture:
{
TexturePtr texture = value.data.value<TexturePtr>();
// Set value to bound texture
shader->setUniformValue(variable_location, textures_to_bind.size());
// If this texture binding is the iterative input, set it here
if (it.key() == job.GetIterativeInput()) {
iterative_input = textures_to_bind.size();
}
GLuint tex_id = texture ? texture->id().value<GLuint>() : 0;
textures_to_bind.append(tex_id);
if (texture && texture->has_meaningful_alpha()) {
input_textures_have_alpha = true;
}
// 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
|| destination_params.pixel_aspect_ratio() != 1) {
double relative_pixel_aspect = texture->params().pixel_aspect_ratio().toDouble() / destination_params.pixel_aspect_ratio().toDouble();
adjusted_width = qRound(static_cast<double>(adjusted_width) * relative_pixel_aspect);
}
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;
}
}
// 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));
PrepareInputTexture(job.GetBilinearFiltering());
}
// Set ove_resolution to the destination to the "logical" resolution of the destination
shader->setUniformValue("ove_resolution",
static_cast<GLfloat>(destination_params.width()),
static_cast<GLfloat>(destination_params.height()));
// Set matrix to identity
shader->setUniformValue("ove_mvpmat", job.GetMatrix());
// Set the viewport to the "physical" resolution of the destination
functions_->glViewport(0, 0,
destination_params.effective_width(),
destination_params.effective_height());
// Bind vertex array object
QOpenGLVertexArrayObject vao_;
vao_.create();
vao_.bind();
// Set buffers
QOpenGLBuffer vert_vbo_;
vert_vbo_.create();
vert_vbo_.bind();
vert_vbo_.allocate(blit_vertices.constData(), blit_vertices.size() * sizeof(GLfloat));
vert_vbo_.release();
QOpenGLBuffer frag_vbo_;
frag_vbo_.create();
frag_vbo_.bind();
frag_vbo_.allocate(blit_texcoords.constData(), blit_texcoords.size() * sizeof(GLfloat));
frag_vbo_.release();
int vertex_location = shader->attributeLocation("a_position");
vert_vbo_.bind();
functions_->glEnableVertexAttribArray(vertex_location);
functions_->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
vert_vbo_.release();
int tex_location = shader->attributeLocation("a_texcoord");
frag_vbo_.bind();
functions_->glEnableVertexAttribArray(tex_location);
functions_->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
frag_vbo_.release();
// Some shaders optimize through multiple iterations which requires ping-ponging textures
// - If there are only two iterations, we can just create one backend texture and then the
// destination can be the second
// - If there are more than two iterations, we need to ping pong back and forth between two
// textures. We can still use the destination as the last iteration, but we'll need textures
// for the iterative process.
int real_iteration_count;
if (job.GetIterationCount() > 1 && !job.GetIterativeInput().isEmpty()) {
real_iteration_count = job.GetIterationCount();
} else {
real_iteration_count = 1;
}
TexturePtr output_tex, input_tex;
if (real_iteration_count > 1) {
// Create one texture to bounce off
output_tex = CreateTexture(destination_params);
if (real_iteration_count > 2) {
// Create a second texture bounce off
input_tex = CreateTexture(destination_params);
}
}
for (int iteration=0; iteration<real_iteration_count; iteration++) {
// Set iteration number
shader->setUniformValue("ove_iteration", iteration);
// Replace iterative input
if (iteration == real_iteration_count-1) {
// This is the last iteration, draw to the destination
if (destination) {
// If we have a destination texture, draw to it
AttachTextureAsDestination(destination);
} else if (iteration > 0) {
// Otherwise, if we were iterating before, detach texture now
DetachTextureAsDestination();
}
} else {
// Always draw to output_tex, which gets swapped with input_tex every iteration
AttachTextureAsDestination(output_tex.get());
}
if (iteration > 0) {
// If this is not the first iteration, replace the iterative texture with the one we
// last drew
functions_->glActiveTexture(GL_TEXTURE0 + iterative_input);
functions_->glBindTexture(GL_TEXTURE_2D, input_tex->id().value<GLuint>());
PrepareInputTexture(job.GetBilinearFiltering());
}
// Swap so that the next iteration, the texture we draw now will be the input texture next
std::swap(output_tex, input_tex);
// Blit this texture through this shader
functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3);
}
if (destination) {
// Reset framebuffer to default if we were drawing to a texture
DetachTextureAsDestination();
// Set metadata for whether this texture has a meaningful alpha channel
destination->set_has_meaningful_alpha((input_textures_have_alpha || job.GetAlphaChannelRequired()));
}
// Release any textures we bound before
for (int i=textures_to_bind.size()-1; i>=0; i--) {
functions_->glActiveTexture(GL_TEXTURE0 + i);
functions_->glBindTexture(GL_TEXTURE_2D, 0);
}
// Release shader
shader->release();
// Release vertex array object
frag_vbo_.destroy();
vert_vbo_.destroy();
vao_.release();
vao_.destroy();
}
GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format)
{
switch (format) {
case PixelFormat::PIX_FMT_RGBA8:
return GL_RGBA8;
case PixelFormat::PIX_FMT_RGBA16U:
return GL_RGBA16;
case PixelFormat::PIX_FMT_RGBA16F:
return GL_RGBA16F;
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::GetPixelType(PixelFormat::Format format)
{
switch (format) {
case PixelFormat::PIX_FMT_RGBA8:
return GL_UNSIGNED_BYTE;
case PixelFormat::PIX_FMT_RGBA16U:
return GL_UNSIGNED_SHORT;
case PixelFormat::PIX_FMT_RGBA16F:
return GL_HALF_FLOAT;
case PixelFormat::PIX_FMT_RGBA32F:
return GL_FLOAT;
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
}
return GL_INVALID_VALUE;
}
void OpenGLRenderer::PrepareInputTexture(bool bilinear)
{
if (bilinear) {
// Use mipmapped bilinear
functions_->glGenerateMipmap(GL_TEXTURE_2D);
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
// Use nearest
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
OLIVE_NAMESPACE_EXIT
@@ -1,95 +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 OPENGLCONTEXT_H
#define OPENGLCONTEXT_H
#include <QOffscreenSurface>
#include <QOpenGLBuffer>
#include <QOpenGLFunctions>
#include <QOpenGLShader>
#include <QOpenGLVertexArrayObject>
#include <QThread>
#include "render/backend/renderer.h"
OLIVE_NAMESPACE_ENTER
class OpenGLRenderer : public Renderer
{
Q_OBJECT
public:
OpenGLRenderer(QObject* parent = nullptr);
virtual ~OpenGLRenderer() override;
void Init(QOpenGLContext* existing_ctx);
virtual bool Init() override;
public slots:
virtual void PostInit() override;
virtual void Destroy() override;
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) override;
virtual void DestroyNativeTexture(QVariant texture) override;
virtual QVariant CreateNativeShader(OLIVE_NAMESPACE::ShaderCode code) override;
virtual void DestroyNativeShader(QVariant shader) override;
virtual void UploadToTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) override;
virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) override;
protected slots:
virtual void Blit(QVariant shader,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::Renderer::Texture* destination,
OLIVE_NAMESPACE::VideoParams destination_params) override;
private:
static GLint GetInternalFormat(PixelFormat::Format format);
static GLenum GetPixelType(PixelFormat::Format format);
void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture);
void DetachTextureAsDestination();
void PrepareInputTexture(bool bilinear);
QOpenGLContext* context_;
QOpenGLFunctions* functions_;
QOffscreenSurface surface_;
GLuint framebuffer_;
};
OLIVE_NAMESPACE_EXIT
#endif // OPENGLCONTEXT_H
-113
View File
@@ -1,113 +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 "renderer.h"
#include <QFloat16>
#include "common/ocioutils.h"
#include "render/colormanager.h"
OLIVE_NAMESPACE_ENTER
Renderer::Renderer(QObject *parent) :
QObject(parent)
{
}
Renderer::TexturePtr Renderer::CreateTexture(const VideoParams &param, void *data, int linesize)
{
QVariant v = CreateNativeTexture(param, data, linesize);
if (v.isNull()) {
return nullptr;
}
return std::make_shared<Texture>(this, v, param);
}
// copied from source code to OCIODisplay
/*const int OCIO_LUT3D_EDGE_SIZE = 64;
const int OCIO_LUT3D_PIXEL_COUNT = OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE;
const int OCIO_LUT3D_ENTRY_COUNT = 3 * OCIO_LUT3D_PIXEL_COUNT;
const int OCIO_LUT3D_ENTRY_COUNT_WITH_ALPHA = 4 * OCIO_LUT3D_PIXEL_COUNT;
const int OCIO_LUT2D_EDGE_SIZE = 512;*/
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture *destination, bool flipped)
{
qDebug() << "BlitColorManaged is a partial stub";
QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert")));
ShaderJob job;
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture));
if (flipped) {
QMatrix4x4 mat;
mat.scale(1, -1, 1);
job.SetMatrix(mat);
}
BlitToTexture(shader, job, destination);
DestroyNativeShader(shader);
}
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params, bool flipped)
{
qDebug() << "BlitColorManaged is a partial stub";
/*ColorContext color_ctx;
if (color_cache_.contains(color_processor->id())) {
color_ctx = color_cache_.value(color_processor->id());
} else {
// Create shader description
const char* ocio_func_name = "OCIODisplay";
OCIO::GpuShaderDescRcPtr shader_desc = OCIO::GpuShaderDesc::CreateShaderDesc();
shader_desc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_2);
shader_desc->setFunctionName(ocio_func_name);
shader_desc->setResourcePrefix("ocio_");
// Generate shader
color_processor->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc);
qDebug() << "Shader:" << shader_desc->getShaderText();
}*/
QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert")));
ShaderJob job;
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture));
if (flipped) {
QMatrix4x4 mat;
mat.scale(1, -1, 1);
job.SetMatrix(mat);
}
Blit(shader, job, params);
DestroyNativeShader(shader);
}
OLIVE_NAMESPACE_EXIT
-180
View File
@@ -1,180 +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 "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 bool Init() = 0;
class Texture
{
public:
Texture(Renderer* renderer, const QVariant& native, const VideoParams& param) :
renderer_(renderer),
params_(param),
id_(native),
meaningful_alpha_(true)
{
}
~Texture()
{
renderer_->DestroyNativeTexture(id_);
}
QVariant id() const
{
return id_;
}
const VideoParams& params() const
{
return params_;
}
void Upload(void* data, int linesize)
{
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();
}
bool has_meaningful_alpha() const
{
return meaningful_alpha_;
}
void set_has_meaningful_alpha(bool e)
{
meaningful_alpha_ = e;
}
private:
Renderer* renderer_;
VideoParams params_;
QVariant id_;
bool meaningful_alpha_;
};
using TexturePtr = std::shared_ptr<Texture>;
TexturePtr CreateTexture(const VideoParams& param, void* data = nullptr, int linesize = 0);
void BlitToTexture(QVariant shader,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::Renderer::Texture* destination)
{
Blit(shader, job, destination, destination->params());
}
void Blit(QVariant shader,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::VideoParams params)
{
Blit(shader, job, nullptr, params);
}
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture* destination, bool flipped = false);
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params, bool flipped = false);
public slots:
virtual void PostInit() = 0;
virtual void Destroy() = 0;
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) = 0;
virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) = 0;
virtual void DestroyNativeTexture(QVariant texture) = 0;
virtual QVariant CreateNativeShader(OLIVE_NAMESPACE::ShaderCode code) = 0;
virtual void DestroyNativeShader(QVariant shader) = 0;
virtual void UploadToTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) = 0;
virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) = 0;
protected slots:
virtual void Blit(QVariant shader,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::Renderer::Texture* destination,
OLIVE_NAMESPACE::VideoParams destination_params) = 0;
private:
struct ColorContext {
QVariant shader;
TexturePtr lut;
};
QHash<QString, ColorContext> color_cache_;
};
OLIVE_NAMESPACE_EXIT
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::Renderer::TexturePtr);
#endif // RENDERCONTEXT_H
@@ -1,142 +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 "rendererthreadwrapper.h"
OLIVE_NAMESPACE_ENTER
RendererThreadWrapper::RendererThreadWrapper(Renderer *inner, QObject *parent) :
Renderer(parent),
inner_(inner),
thread_(nullptr)
{
}
bool RendererThreadWrapper::Init()
{
// Init context in main thread
if (!inner_->Init()) {
return false;
}
// Create thread
thread_ = new QThread(this);
thread_->start(QThread::IdlePriority);
// Move context to thread
inner_->moveToThread(thread_);
// Queue post-init in new thread
QMetaObject::invokeMethod(inner_, "PostInit", Qt::BlockingQueuedConnection);
return true;
}
void RendererThreadWrapper::PostInit()
{
// Do nothing
}
void RendererThreadWrapper::Destroy()
{
if (thread_) {
QMetaObject::invokeMethod(inner_, "Destroy", Qt::BlockingQueuedConnection);
inner_ = nullptr;
thread_->quit();
thread_->wait();
delete thread_;
thread_ = nullptr;
}
}
void RendererThreadWrapper::ClearDestination(double r, double g, double b, double a)
{
QMetaObject::invokeMethod(inner_, "ClearDestination", Qt::BlockingQueuedConnection,
Q_ARG(double, r),
Q_ARG(double, g),
Q_ARG(double, b),
Q_ARG(double, a));
}
QVariant RendererThreadWrapper::CreateNativeTexture(VideoParams param, void *data, int linesize)
{
QVariant v;
QMetaObject::invokeMethod(inner_, "CreateNativeTexture", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QVariant, v),
OLIVE_NS_ARG(VideoParams, param),
Q_ARG(void*, data),
Q_ARG(int, linesize));
return v;
}
void RendererThreadWrapper::DestroyNativeTexture(QVariant texture)
{
QMetaObject::invokeMethod(inner_, "DestroyNativeTexture", Qt::BlockingQueuedConnection,
Q_ARG(QVariant, texture));
}
QVariant RendererThreadWrapper::CreateNativeShader(ShaderCode code)
{
QVariant v;
QMetaObject::invokeMethod(inner_, "CreateNativeShader", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QVariant, v),
OLIVE_NS_ARG(ShaderCode, code));
return v;
}
void RendererThreadWrapper::DestroyNativeShader(QVariant shader)
{
QMetaObject::invokeMethod(inner_, "DestroyNativeShader", Qt::BlockingQueuedConnection,
Q_ARG(QVariant, shader));
}
void RendererThreadWrapper::UploadToTexture(Renderer::Texture *texture, void *data, int linesize)
{
QMetaObject::invokeMethod(inner_, "UploadToTexture", Qt::BlockingQueuedConnection,
OLIVE_NS_ARG(Renderer::Texture*, texture),
Q_ARG(void*, data),
Q_ARG(int, linesize));
}
void RendererThreadWrapper::DownloadFromTexture(Renderer::Texture *texture, void *data, int linesize)
{
QMetaObject::invokeMethod(inner_, "DownloadFromTexture", Qt::BlockingQueuedConnection,
OLIVE_NS_ARG(Renderer::Texture*, texture),
Q_ARG(void*, data),
Q_ARG(int, linesize));
}
void RendererThreadWrapper::Blit(QVariant shader, ShaderJob job, Renderer::Texture *destination, VideoParams destination_params)
{
Renderer::TexturePtr tex;
QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection,
Q_ARG(QVariant, shader),
OLIVE_NS_ARG(ShaderJob, job),
OLIVE_NS_ARG(Renderer::Texture*, destination),
OLIVE_NS_ARG(VideoParams, destination_params));
}
OLIVE_NAMESPACE_EXIT
@@ -1,77 +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 RENDERCONTEXTTHREADWRAPPER_H
#define RENDERCONTEXTTHREADWRAPPER_H
#include <QThread>
#include "renderer.h"
OLIVE_NAMESPACE_ENTER
class RendererThreadWrapper : public Renderer
{
public:
RendererThreadWrapper(Renderer* inner, QObject* parent = nullptr);
virtual ~RendererThreadWrapper() override
{
Destroy();
delete inner_;
}
virtual bool Init() override;
public slots:
virtual void PostInit() override;
virtual void Destroy() override;
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) override;
virtual void DestroyNativeTexture(QVariant texture) override;
virtual QVariant CreateNativeShader(OLIVE_NAMESPACE::ShaderCode code) override;
virtual void DestroyNativeShader(QVariant shader) override;
virtual void UploadToTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) override;
virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) override;
protected slots:
virtual void Blit(QVariant shader,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::Renderer::Texture* destination,
OLIVE_NAMESPACE::VideoParams destination_params) override;
private:
Renderer* inner_;
QThread* thread_;
};
OLIVE_NAMESPACE_EXIT
#endif // RENDERCONTEXTTHREADWRAPPER_H