okay maybe not
This commit is contained in:
@@ -44,6 +44,7 @@ set(OLIVE_SOURCES
|
|||||||
common/ratiodialog.cpp
|
common/ratiodialog.cpp
|
||||||
common/rational.h
|
common/rational.h
|
||||||
common/rational.cpp
|
common/rational.cpp
|
||||||
|
common/threadsafemap.h
|
||||||
common/threadedobject.h
|
common/threadedobject.h
|
||||||
common/threadedobject.cpp
|
common/threadedobject.cpp
|
||||||
common/timecodefunctions.h
|
common/timecodefunctions.h
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef THREADSAFEMAP_H
|
||||||
|
#define THREADSAFEMAP_H
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
|
template <typename K, typename V>
|
||||||
|
class ThreadSafeMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ThreadSafeMap() = default;
|
||||||
|
|
||||||
|
void insert(K key, V value)
|
||||||
|
{
|
||||||
|
mutex_.lock();
|
||||||
|
map_.insert(key, value);
|
||||||
|
mutex_.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutex mutex_;
|
||||||
|
|
||||||
|
QMap<K, V> map_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // THREADSAFEMAP_H
|
||||||
@@ -49,6 +49,7 @@ set(OLIVE_SOURCES
|
|||||||
render/renderprocessor.h
|
render/renderprocessor.h
|
||||||
render/renderprocessor.cpp
|
render/renderprocessor.cpp
|
||||||
render/shaderinfo.h
|
render/shaderinfo.h
|
||||||
|
render/stillimagecache.h
|
||||||
render/videoparams.h
|
render/videoparams.h
|
||||||
render/videoparams.cpp
|
render/videoparams.cpp
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
|
|||||||
@@ -24,6 +24,36 @@
|
|||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
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
|
||||||
|
};
|
||||||
|
|
||||||
OpenGLRenderer::OpenGLRenderer(QObject* parent) :
|
OpenGLRenderer::OpenGLRenderer(QObject* parent) :
|
||||||
Renderer(parent),
|
Renderer(parent),
|
||||||
context_(nullptr)
|
context_(nullptr)
|
||||||
@@ -75,18 +105,45 @@ void OpenGLRenderer::PostInit()
|
|||||||
// Store OpenGL functions instance
|
// Store OpenGL functions instance
|
||||||
functions_ = context_->functions();
|
functions_ = context_->functions();
|
||||||
functions_->glBlendFunc(GL_ONE, GL_ZERO);
|
functions_->glBlendFunc(GL_ONE, GL_ZERO);
|
||||||
|
|
||||||
|
// Set up framebuffer used for various things
|
||||||
|
functions_->glGenFramebuffers(1, &framebuffer_);
|
||||||
|
|
||||||
|
// Set up vertex array object
|
||||||
|
vao_.create();
|
||||||
|
|
||||||
|
// Set up vertex buffer
|
||||||
|
vert_vbo_.create();
|
||||||
|
vert_vbo_.bind();
|
||||||
|
vert_vbo_.allocate(blit_vertices.constData(), blit_vertices.size() * sizeof(GLfloat));
|
||||||
|
vert_vbo_.release();
|
||||||
|
|
||||||
|
// Set up fragment buffer
|
||||||
|
frag_vbo_.create();
|
||||||
|
frag_vbo_.bind();
|
||||||
|
frag_vbo_.allocate(blit_texcoords.constData(), blit_texcoords.size() * sizeof(GLfloat));
|
||||||
|
frag_vbo_.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLRenderer::Destroy()
|
void OpenGLRenderer::Destroy()
|
||||||
{
|
{
|
||||||
|
// Delete vertex array object
|
||||||
|
vao_.destroy();
|
||||||
|
|
||||||
|
// Delete framebuffer
|
||||||
|
functions_->glDeleteFramebuffers(1, &framebuffer_);
|
||||||
|
|
||||||
|
// Delete all shaders
|
||||||
|
qDeleteAll(shader_cache_);
|
||||||
|
shader_cache_.clear();
|
||||||
|
|
||||||
|
// Delete context if it belongs to us
|
||||||
if (context_->parent() == this) {
|
if (context_->parent() == this) {
|
||||||
delete context_;
|
delete context_;
|
||||||
}
|
}
|
||||||
context_ = nullptr;
|
context_ = nullptr;
|
||||||
|
|
||||||
qDeleteAll(shader_cache_);
|
// Destroy surface if we created it
|
||||||
shader_cache_.clear();
|
|
||||||
|
|
||||||
if (surface_.isValid()) {
|
if (surface_.isValid()) {
|
||||||
surface_.destroy();
|
surface_.destroy();
|
||||||
}
|
}
|
||||||
@@ -183,11 +240,11 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (frag_code.isEmpty()) {
|
if (frag_code.isEmpty()) {
|
||||||
frag_code = OpenGLShader::CodeDefaultFragment();
|
frag_code = Node::ReadFileAsString(QStringLiteral(":/shaders/default.frag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vert_code.isEmpty()) {
|
if (vert_code.isEmpty()) {
|
||||||
vert_code = OpenGLShader::CodeDefaultVertex();
|
vert_code = Node::ReadFileAsString(QStringLiteral(":/shaders/default.vert"));
|
||||||
}
|
}
|
||||||
|
|
||||||
shader = new QOpenGLShaderProgram(this);
|
shader = new QOpenGLShaderProgram(this);
|
||||||
@@ -354,8 +411,6 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
|||||||
static_cast<GLfloat>(params.width()),
|
static_cast<GLfloat>(params.width()),
|
||||||
static_cast<GLfloat>(params.height()));
|
static_cast<GLfloat>(params.height()));
|
||||||
|
|
||||||
shader->release();
|
|
||||||
|
|
||||||
// Create the output textures
|
// Create the output textures
|
||||||
PixelFormat::Format output_format = (input_textures_have_alpha || job.GetAlphaChannelRequired())
|
PixelFormat::Format output_format = (input_textures_have_alpha || job.GetAlphaChannelRequired())
|
||||||
? PixelFormat::GetFormatWithAlphaChannel(params.format())
|
? PixelFormat::GetFormatWithAlphaChannel(params.format())
|
||||||
@@ -393,14 +448,28 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
|||||||
for (int i=0; i<textures_to_bind.size(); i++) {
|
for (int i=0; i<textures_to_bind.size(); i++) {
|
||||||
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
||||||
functions_->glBindTexture(GL_TEXTURE_2D, textures_to_bind.at(i));
|
functions_->glBindTexture(GL_TEXTURE_2D, textures_to_bind.at(i));
|
||||||
OpenGLRenderFunctions::PrepareToDraw(functions_);
|
PrepareInputTexture(job.GetBilinearFiltering());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bind vertex array object
|
||||||
|
vao_.bind();
|
||||||
|
|
||||||
|
// Set buffers
|
||||||
|
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();
|
||||||
|
|
||||||
for (int iteration=0; iteration<real_iteration_count; iteration++) {
|
for (int iteration=0; iteration<real_iteration_count; iteration++) {
|
||||||
// Set iteration number
|
// Set iteration number
|
||||||
shader->bind();
|
|
||||||
shader->setUniformValue("ove_iteration", iteration);
|
shader->setUniformValue("ove_iteration", iteration);
|
||||||
shader->release();
|
|
||||||
|
|
||||||
// Replace iterative input
|
// Replace iterative input
|
||||||
if (iteration == 0) {
|
if (iteration == 0) {
|
||||||
@@ -410,18 +479,22 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
|||||||
output_tex = dst_refs[iteration%2];
|
output_tex = dst_refs[iteration%2];
|
||||||
|
|
||||||
functions_->glActiveTexture(GL_TEXTURE0 + iterative_input);
|
functions_->glActiveTexture(GL_TEXTURE0 + iterative_input);
|
||||||
functions_->glBindTexture(GL_TEXTURE_2D, input_tex->texture()->texture());
|
functions_->glBindTexture(GL_TEXTURE_2D, input_tex->id().value<GLuint>());
|
||||||
OpenGLRenderFunctions::PrepareToDraw(functions_);
|
PrepareInputTexture(job.GetBilinearFiltering());
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_.Attach(output_tex, true);
|
functions_->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
|
||||||
buffer_.Bind();
|
functions_->glFramebufferTexture2D(GL_FRAMEBUFFER,
|
||||||
|
GL_COLOR_ATTACHMENT0,
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
output_tex->id().value<GLuint>(),
|
||||||
|
0);
|
||||||
|
|
||||||
// Blit this texture through this shader
|
// Blit this texture through this shader
|
||||||
OpenGLRenderFunctions::Blit(shader);
|
functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3);
|
||||||
|
|
||||||
buffer_.Release();
|
// Reset framebuffer to default
|
||||||
buffer_.Detach();
|
functions_->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release any textures we bound before
|
// Release any textures we bound before
|
||||||
@@ -430,16 +503,15 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
|||||||
functions_->glBindTexture(GL_TEXTURE_2D, 0);
|
functions_->glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Release vertex array object
|
||||||
|
vao_.release();
|
||||||
|
|
||||||
|
// Release shader
|
||||||
|
shader->release();
|
||||||
|
|
||||||
return output_tex;
|
return output_tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*VideoParams OpenGLRenderer::GetParamsFromTexture(QVariant texture)
|
|
||||||
{
|
|
||||||
GLuint t = texture.value<GLuint>();
|
|
||||||
|
|
||||||
return texture_params_.value(t);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format)
|
GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format)
|
||||||
{
|
{
|
||||||
switch (format) {
|
switch (format) {
|
||||||
@@ -501,4 +573,21 @@ GLenum OpenGLRenderer::GetPixelType(PixelFormat::Format format)
|
|||||||
return GL_INVALID_VALUE;
|
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
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|||||||
@@ -22,8 +22,10 @@
|
|||||||
#define OPENGLCONTEXT_H
|
#define OPENGLCONTEXT_H
|
||||||
|
|
||||||
#include <QOffscreenSurface>
|
#include <QOffscreenSurface>
|
||||||
|
#include <QOpenGLBuffer>
|
||||||
#include <QOpenGLFunctions>
|
#include <QOpenGLFunctions>
|
||||||
#include <QOpenGLShader>
|
#include <QOpenGLShader>
|
||||||
|
#include <QOpenGLVertexArrayObject>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
#include "render/backend/renderer.h"
|
#include "render/backend/renderer.h"
|
||||||
@@ -60,7 +62,7 @@ public slots:
|
|||||||
const OLIVE_NAMESPACE::ShaderJob &job,
|
const OLIVE_NAMESPACE::ShaderJob &job,
|
||||||
const OLIVE_NAMESPACE::VideoParams ¶ms) override;
|
const OLIVE_NAMESPACE::VideoParams ¶ms) override;
|
||||||
|
|
||||||
virtual QVariant TransformColor(QVariant texture, ColorProcessorPtr processor) override;
|
virtual TexturePtr TransformColor(Texture* texture, OLIVE_NAMESPACE::ColorProcessorPtr processor) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static GLint GetInternalFormat(PixelFormat::Format format);
|
static GLint GetInternalFormat(PixelFormat::Format format);
|
||||||
@@ -69,12 +71,22 @@ private:
|
|||||||
|
|
||||||
static GLenum GetPixelType(PixelFormat::Format format);
|
static GLenum GetPixelType(PixelFormat::Format format);
|
||||||
|
|
||||||
|
void PrepareInputTexture(bool bilinear);
|
||||||
|
|
||||||
QOpenGLContext* context_;
|
QOpenGLContext* context_;
|
||||||
|
|
||||||
QOpenGLFunctions* functions_;
|
QOpenGLFunctions* functions_;
|
||||||
|
|
||||||
QOffscreenSurface surface_;
|
QOffscreenSurface surface_;
|
||||||
|
|
||||||
|
QOpenGLVertexArrayObject vao_;
|
||||||
|
|
||||||
|
QOpenGLBuffer vert_vbo_;
|
||||||
|
|
||||||
|
QOpenGLBuffer frag_vbo_;
|
||||||
|
|
||||||
|
GLuint framebuffer_;
|
||||||
|
|
||||||
QHash<QString, QOpenGLShaderProgram*> shader_cache_;
|
QHash<QString, QOpenGLShaderProgram*> shader_cache_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -132,7 +132,7 @@ public slots:
|
|||||||
const OLIVE_NAMESPACE::ShaderJob &job,
|
const OLIVE_NAMESPACE::ShaderJob &job,
|
||||||
const OLIVE_NAMESPACE::VideoParams ¶ms) = 0;
|
const OLIVE_NAMESPACE::VideoParams ¶ms) = 0;
|
||||||
|
|
||||||
virtual QVariant TransformColor(QVariant texture, OLIVE_NAMESPACE::ColorProcessorPtr processor) = 0;
|
virtual TexturePtr TransformColor(Texture* texture, OLIVE_NAMESPACE::ColorProcessorPtr processor) = 0;
|
||||||
|
|
||||||
virtual void Render() = 0;
|
virtual void Render() = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, const rational
|
|||||||
ticket->setProperty("matrix", matrix);
|
ticket->setProperty("matrix", matrix);
|
||||||
ticket->setProperty("mode", mode);
|
ticket->setProperty("mode", mode);
|
||||||
ticket->setProperty("type", kTypeVideo);
|
ticket->setProperty("type", kTypeVideo);
|
||||||
|
ticket->setProperty("cache", viewer->video_frame_cache()->GetCacheDirectory());
|
||||||
|
|
||||||
// Queue appending the ticket and running the next job on our thread to make this function thread-safe
|
// Queue appending the ticket and running the next job on our thread to make this function thread-safe
|
||||||
QMetaObject::invokeMethod(this, "AddTicket", Qt::AutoConnection,
|
QMetaObject::invokeMethod(this, "AddTicket", Qt::AutoConnection,
|
||||||
|
|||||||
@@ -197,30 +197,59 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const TrackOutput *track, con
|
|||||||
|
|
||||||
QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &input_time)
|
QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &input_time)
|
||||||
{
|
{
|
||||||
|
Renderer::TexturePtr value = nullptr;
|
||||||
|
|
||||||
|
// Check the still frame cache. On large frames such as high resolution still images, uploading
|
||||||
|
// and color managing them for every frame is a waste of time, so we implement a small cache here
|
||||||
|
// to optimize such a situation
|
||||||
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(stream);
|
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(stream);
|
||||||
rational time_match = (video_stream->video_type() == VideoStream::kVideoTypeStill) ? 0 : input_time;
|
|
||||||
QString colorspace_match = video_stream->get_colorspace_match_string();
|
|
||||||
|
|
||||||
QVariant value;
|
|
||||||
bool found_cache = false;
|
|
||||||
|
|
||||||
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
|
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
|
||||||
|
StillImageCache::Entry want_entry = {nullptr,
|
||||||
|
stream,
|
||||||
|
video_stream->get_colorspace_match_string(),
|
||||||
|
video_stream->premultiplied_alpha(),
|
||||||
|
video_params.divider(),
|
||||||
|
(video_stream->video_type() == VideoStream::kVideoTypeStill) ? 0 : input_time};
|
||||||
|
|
||||||
if (still_image_cache_.contains(stream.get())) {
|
still_image_cache_->mutex()->lock();
|
||||||
const CachedStill& cs = still_image_cache_[stream.get()];
|
|
||||||
|
|
||||||
if (cs.colorspace == colorspace_match
|
foreach (const StillImageCache::Entry& e, still_image_cache_->entries()) {
|
||||||
&& cs.alpha_is_associated == video_stream->premultiplied_alpha()
|
if (StillImageCache::CompareEntryMetadata(want_entry, e)) {
|
||||||
&& cs.divider == video_params.divider()
|
// Found an exact match of the texture we want in the cache, use it instead of reading it
|
||||||
&& cs.time == time_match) {
|
// ourselves
|
||||||
value = cs.texture;
|
value = e.texture;
|
||||||
found_cache = true;
|
break;
|
||||||
} else {
|
|
||||||
still_image_cache_.remove(stream.get());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found_cache) {
|
if (!value) {
|
||||||
|
// Failed to find the texture, let's see if it's being generated by another processor
|
||||||
|
foreach (const StillImageCache::Entry& e, still_image_cache_->pending()) {
|
||||||
|
if (StillImageCache::CompareEntryMetadata(want_entry, e)) {
|
||||||
|
// An exact match of this texture is pending, let's wait for it
|
||||||
|
while (!value) {
|
||||||
|
// FIXME: Hacky way of waiting for other threads
|
||||||
|
still_image_cache_->mutex()->unlock();
|
||||||
|
QThread::msleep(1);
|
||||||
|
still_image_cache_->mutex()->lock();
|
||||||
|
|
||||||
|
value = e.texture;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
// Found the texture, we can release the cache now
|
||||||
|
still_image_cache_->mutex()->unlock();
|
||||||
|
} else {
|
||||||
|
// Wasn't in still image cache, so we'll have to retrieve it from the decoder
|
||||||
|
|
||||||
|
// Let other processors know we're getting this texture
|
||||||
|
still_image_cache_->PushPending(want_entry);
|
||||||
|
|
||||||
|
still_image_cache_->mutex()->unlock();
|
||||||
|
|
||||||
DecoderPtr decoder = ResolveDecoderFromInput(stream);
|
DecoderPtr decoder = ResolveDecoderFromInput(stream);
|
||||||
|
|
||||||
@@ -230,22 +259,26 @@ QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &
|
|||||||
|
|
||||||
if (frame) {
|
if (frame) {
|
||||||
// Return a texture from the derived class
|
// Return a texture from the derived class
|
||||||
|
Renderer::TexturePtr unmanaged_texture = render_ctx_->CreateTexture(frame->video_params(), frame->data(), frame->linesize_pixels());
|
||||||
|
|
||||||
|
Renderer::TexturePtr managed_texture = render_ctx_->TransformColor(unmanaged_texture, )
|
||||||
|
|
||||||
value = FootageFrameToTexture(stream, frame);
|
value = FootageFrameToTexture(stream, frame);
|
||||||
|
|
||||||
if (!value.isNull()) {
|
still_image_cache_->mutex()->lock();
|
||||||
// Put this into the image cache instead
|
|
||||||
still_image_cache_.insert(stream.get(), {value,
|
still_image_cache_->RemovePending(want_entry);
|
||||||
colorspace_match,
|
|
||||||
video_stream->premultiplied_alpha(),
|
// Put this into the image cache instead
|
||||||
video_params .divider(),
|
want_entry.texture = value;
|
||||||
time_match});
|
still_image_cache_->PushEntry(want_entry);
|
||||||
}
|
|
||||||
|
still_image_cache_->mutex()->unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return QVariant::fromValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant RenderProcessor::ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time)
|
QVariant RenderProcessor::ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time)
|
||||||
@@ -369,7 +402,9 @@ QVariant RenderProcessor::ProcessFrameGeneration(const Node *node, const Generat
|
|||||||
|
|
||||||
node->GenerateFrame(frame, job);
|
node->GenerateFrame(frame, job);
|
||||||
|
|
||||||
return CachedFrameToTexture(frame);
|
Renderer::TexturePtr texture = render_ctx_->CreateTexture(frame->video_params(), frame->data(), frame->linesize_pixels());
|
||||||
|
|
||||||
|
return QVariant::fromValue(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant RenderProcessor::GetCachedFrame(const Node *node, const rational &time)
|
QVariant RenderProcessor::GetCachedFrame(const Node *node, const rational &time)
|
||||||
@@ -393,7 +428,8 @@ QVariant RenderProcessor::GetCachedFrame(const Node *node, const rational &time)
|
|||||||
f->video_params().interlacing(),
|
f->video_params().interlacing(),
|
||||||
video_params.divider()));
|
video_params.divider()));
|
||||||
|
|
||||||
return CachedFrameToTexture(f);
|
Renderer::TexturePtr texture = render_ctx_->CreateTexture(f->video_params(), f->data(), f->linesize_pixels());
|
||||||
|
return QVariant::fromValue(texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "node/traverser.h"
|
#include "node/traverser.h"
|
||||||
#include "render/backend/renderer.h"
|
#include "render/backend/renderer.h"
|
||||||
|
#include "stillimagecache.h"
|
||||||
#include "threading/threadticket.h"
|
#include "threading/threadticket.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
@@ -68,6 +69,8 @@ private:
|
|||||||
|
|
||||||
Renderer* render_ctx_;
|
Renderer* render_ctx_;
|
||||||
|
|
||||||
|
StillImageCache* still_image_cache_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ public:
|
|||||||
{
|
{
|
||||||
iterations_ = 1;
|
iterations_ = 1;
|
||||||
iterative_input_ = nullptr;
|
iterative_input_ = nullptr;
|
||||||
|
bilinear_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString& GetShaderID() const
|
const QString& GetShaderID() const
|
||||||
@@ -150,6 +151,16 @@ public:
|
|||||||
return iterative_input_;
|
return iterative_input_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetBilinearFiltering() const
|
||||||
|
{
|
||||||
|
return bilinear_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBilinearFiltering(bool e)
|
||||||
|
{
|
||||||
|
bilinear_ = e;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString id_;
|
QString id_;
|
||||||
|
|
||||||
@@ -157,6 +168,8 @@ private:
|
|||||||
|
|
||||||
NodeInput* iterative_input_;
|
NodeInput* iterative_input_;
|
||||||
|
|
||||||
|
bool bilinear_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderCode {
|
class ShaderCode {
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#ifndef STILLIMAGECACHE_H
|
||||||
|
#define STILLIMAGECACHE_H
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
#include "common/rational.h"
|
||||||
|
#include "project/item/footage/stream.h"
|
||||||
|
#include "render/backend/renderer.h"
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
|
class StillImageCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Entry {
|
||||||
|
Renderer::TexturePtr texture;
|
||||||
|
StreamPtr stream;
|
||||||
|
QString colorspace;
|
||||||
|
bool alpha_is_associated;
|
||||||
|
int divider;
|
||||||
|
rational time;
|
||||||
|
};
|
||||||
|
|
||||||
|
QMutex* mutex()
|
||||||
|
{
|
||||||
|
return &mutex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVector<Entry>& entries() const
|
||||||
|
{
|
||||||
|
return entries_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVector<Entry>& pending() const
|
||||||
|
{
|
||||||
|
return pending_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool CompareEntryMetadata(const Entry& a, const Entry& b)
|
||||||
|
{
|
||||||
|
return (a.stream == b.stream
|
||||||
|
&& a.colorspace == b.colorspace
|
||||||
|
&& a.alpha_is_associated == b.alpha_is_associated
|
||||||
|
&& a.divider == b.divider
|
||||||
|
&& a.time == b.time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushPending(const Entry& e)
|
||||||
|
{
|
||||||
|
pending_.prepend(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushEntry(const Entry& e)
|
||||||
|
{
|
||||||
|
entries_.prepend(e);
|
||||||
|
|
||||||
|
if (entries_.size() > 8) {
|
||||||
|
entries_.removeLast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemovePending(const Entry& e)
|
||||||
|
{
|
||||||
|
for (int i=0; i<pending_.size(); i++) {
|
||||||
|
if (CompareEntryMetadata(pending_.at(i), e)) {
|
||||||
|
pending_.removeAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutex mutex_;
|
||||||
|
|
||||||
|
QVector<Entry> entries_;
|
||||||
|
|
||||||
|
QVector<Entry> pending_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|
||||||
|
#endif // STILLIMAGECACHE_H
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#version 150
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp int;
|
||||||
|
precision highp float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Input texture
|
||||||
|
uniform sampler2D ove_maintex;
|
||||||
|
|
||||||
|
// Input texture coordinate
|
||||||
|
in vec2 ove_texcoord;
|
||||||
|
|
||||||
|
// Output color
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 using_texcoord = ove_texcoord;
|
||||||
|
vec4 color = texture(ove_maintex, ove_texcoord);
|
||||||
|
fragColor = color;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#version 150
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp int;
|
||||||
|
precision highp float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform mat4 ove_mvpmat;
|
||||||
|
|
||||||
|
in vec4 a_position;
|
||||||
|
in vec2 a_texcoord;
|
||||||
|
|
||||||
|
out vec2 ove_texcoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = ove_mvpmat * a_position;
|
||||||
|
ove_texcoord = a_texcoord;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#version 150
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp int;
|
||||||
|
precision highp float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform sampler2D ove_maintex;
|
||||||
|
uniform vec2 ove_resolution;
|
||||||
|
|
||||||
|
in vec2 ove_texcoord;
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 using_texcoord = ove_texcoord;
|
||||||
|
|
||||||
|
// A very basic deinterlace that halves the vertical
|
||||||
|
// resolution and linearly interpolates the two fields
|
||||||
|
// by reading the texture coord between them.
|
||||||
|
float half_vert = round(ove_resolution.y / 2.0);
|
||||||
|
using_texcoord.y = (round(using_texcoord.y * half_vert) + 0.25) / half_vert;
|
||||||
|
|
||||||
|
vec4 color = %1(texture(ove_maintex, using_texcoord));
|
||||||
|
fragColor = color;
|
||||||
|
}
|
||||||
@@ -65,13 +65,13 @@ bool ExportTask::Run()
|
|||||||
|
|
||||||
// If a transformation matrix is applied to this video, create it here
|
// If a transformation matrix is applied to this video, create it here
|
||||||
if (params_.video_scaling_method() != ExportParams::kStretch) {
|
if (params_.video_scaling_method() != ExportParams::kStretch) {
|
||||||
QMatrix4x4 mat = ExportParams::GenerateMatrix(params_.video_scaling_method(),
|
// FIXME: Re-implement this
|
||||||
|
|
||||||
|
/*QMatrix4x4 mat = ExportParams::GenerateMatrix(params_.video_scaling_method(),
|
||||||
viewer()->video_params().width(),
|
viewer()->video_params().width(),
|
||||||
viewer()->video_params().height(),
|
viewer()->video_params().height(),
|
||||||
params_.video_params().width(),
|
params_.video_params().width(),
|
||||||
params_.video_params().height());
|
params_.video_params().height());*/
|
||||||
|
|
||||||
// FIXME: Re-implement this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create color processor
|
// Create color processor
|
||||||
|
|||||||
@@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
|
||||||
#include "render/backend/opengl/openglrenderfunctions.h"
|
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
ColorSwatchWidget::ColorSwatchWidget(QWidget *parent) :
|
ColorSwatchWidget::ColorSwatchWidget(QWidget *parent) :
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
|
|
||||||
#include "render/backend/opengl/openglshader.h"
|
|
||||||
#include "render/color.h"
|
#include "render/color.h"
|
||||||
#include "render/colorprocessor.h"
|
#include "render/colorprocessor.h"
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
|
|
||||||
#include "colorswatchwidget.h"
|
#include "colorswatchwidget.h"
|
||||||
#include "render/backend/opengl/openglshader.h"
|
|
||||||
#include "render/color.h"
|
#include "render/color.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ WaveformScope::WaveformScope(QWidget* parent) :
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLShaderPtr WaveformScope::CreateShader()
|
QVariant WaveformScope::CreateShader()
|
||||||
{
|
{
|
||||||
OpenGLShaderPtr pipeline = OpenGLShader::Create();
|
OpenGLShaderPtr pipeline = OpenGLShader::Create();
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
WaveformScope(QWidget* parent = nullptr);
|
WaveformScope(QWidget* parent = nullptr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual OpenGLShaderPtr CreateShader() override;
|
virtual QVariant CreateShader() override;
|
||||||
|
|
||||||
virtual void DrawScope() override;
|
virtual void DrawScope() override;
|
||||||
|
|
||||||
|
|||||||
@@ -94,8 +94,6 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI
|
|||||||
painter->setPen(QColor(64, 64, 64));
|
painter->setPen(QColor(64, 64, 64));
|
||||||
TrackOutput* track = TrackOutput::TrackFromBlock(block_);
|
TrackOutput* track = TrackOutput::TrackFromBlock(block_);
|
||||||
if (track) {
|
if (track) {
|
||||||
QMutexLocker locker(track->waveform_lock());
|
|
||||||
|
|
||||||
AudioVisualWaveform::DrawWaveform(painter,
|
AudioVisualWaveform::DrawWaveform(painter,
|
||||||
rect().toRect(),
|
rect().toRect(),
|
||||||
this->GetScale(),
|
this->GetScale(),
|
||||||
|
|||||||
@@ -22,10 +22,9 @@
|
|||||||
#define VIEWERGLWIDGET_H
|
#define VIEWERGLWIDGET_H
|
||||||
|
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
|
#include <QMatrix4x4>
|
||||||
|
|
||||||
#include "node/node.h"
|
#include "node/node.h"
|
||||||
#include "render/backend/opengl/openglcolorprocessor.h"
|
|
||||||
#include "render/backend/opengl/openglshader.h"
|
|
||||||
#include "render/color.h"
|
#include "render/color.h"
|
||||||
#include "render/colormanager.h"
|
#include "render/colormanager.h"
|
||||||
#include "tool/tool.h"
|
#include "tool/tool.h"
|
||||||
|
|||||||
Reference in New Issue
Block a user