merged all drawing functions into a single shader processing function

This commit is contained in:
itsmattkc
2020-11-10 15:50:13 +11:00
parent 1d61f89920
commit 0429e70fe0
46 changed files with 570 additions and 398 deletions
+2 -1
View File
@@ -30,7 +30,6 @@ set(OLIVE_SOURCES
render/colorprocessor.h
render/colorprocessorcache.h
render/colorprocessor.cpp
render/decodercache.h
render/diskmanager.h
render/diskmanager.cpp
render/framehashcache.h
@@ -43,12 +42,14 @@ set(OLIVE_SOURCES
render/playbackcache.cpp
render/previewautocacher.h
render/previewautocacher.cpp
render/rendercache.h
render/rendermanager.h
render/rendermanager.cpp
render/rendermodes.h
render/renderprocessor.h
render/renderprocessor.cpp
render/shaderinfo.h
render/shadervalue.h
render/stillimagecache.h
render/videoparams.h
render/videoparams.cpp
+84 -119
View File
@@ -140,10 +140,6 @@ void OpenGLRenderer::Destroy()
// Delete framebuffer
functions_->glDeleteFramebuffers(1, &framebuffer_);
// Delete all shaders
qDeleteAll(shader_cache_);
shader_cache_.clear();
// Delete context if it belongs to us
if (context_->parent() == this) {
delete context_;
@@ -171,8 +167,6 @@ void OpenGLRenderer::AttachTextureAsDestination(Renderer::Texture* texture)
GL_TEXTURE_2D,
texture->id().value<GLuint>(),
0);
SetViewport(texture->width(), texture->height());
}
void OpenGLRenderer::DetachTextureAsDestination()
@@ -221,6 +215,8 @@ QVariant OpenGLRenderer::CreateNativeShader(ShaderCode code)
goto error;
}
qDebug() << "Shader created successfully";
return Node::PtrToValue(program);
error:
@@ -281,51 +277,14 @@ void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int lines
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
}
Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob job, VideoParams params)
void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destination, VideoParams destination_params)
{
// If this node is iterative, we'll pick up which input here
GLuint iterative_input = 0;
QList<GLuint> textures_to_bind;
bool input_textures_have_alpha = false;
QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), job.GetShaderID());
QOpenGLShaderProgram* shader = shader_cache_.value(full_shader_id);
if (!shader) {
// Since we have shader code, compile it now
ShaderCode code = node->GetShaderCode(job.GetShaderID());
QString vert_code = code.vert_code();
QString frag_code = code.frag_code();
if (frag_code.isEmpty() && vert_code.isEmpty()) {
qWarning() << "No shader code found for" << node->id() << "- operation will be a no-op";
}
if (frag_code.isEmpty()) {
frag_code = Node::ReadFileAsString(QStringLiteral(":/shaders/default.frag"));
}
if (vert_code.isEmpty()) {
vert_code = Node::ReadFileAsString(QStringLiteral(":/shaders/default.vert"));
}
shader = new QOpenGLShaderProgram(this);
if (shader
&& shader->create()
&& shader->addShaderFromSourceCode(QOpenGLShader::Fragment, frag_code)
&& shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_code)
&& shader->link()) {
shader_cache_.insert(full_shader_id, shader);
} else {
qWarning() << "Failed to compile shader for" << node->id();
shader = nullptr;
}
if (!shader) {
// Couldn't find or build the shader required
return nullptr;
}
}
QOpenGLShaderProgram* shader = Node::ValueToPtr<QOpenGLShaderProgram>(s);
shader->bind();
@@ -338,28 +297,25 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
continue;
}
// See if this value corresponds to an input (NOTE: it may not and this may be null)
NodeInput* corresponding_input = node->GetInputWithID(it.key());
// This variable is used in the shader, let's set it
const QVariant& value = it.value().data();
const ShaderValue& value = it.value();
NodeParam::DataType data_type = (it.value().type() != NodeParam::kNone)
? it.value().type()
: corresponding_input->data_type();
if (value.array) {
qWarning() << "FIXME: Array support is currently a stub";
}
switch (data_type) {
switch (value.type) {
case NodeInput::kInt:
// kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to
// over/underflows if the number is large enough, but the likelihood of that is quite low.
shader->setUniformValue(variable_location, value.toInt());
shader->setUniformValue(variable_location, value.data.toInt());
break;
case NodeInput::kFloat:
// kFloat technically specifies a double but as above, OpenGL doesn't support those.
shader->setUniformValue(variable_location, value.toFloat());
shader->setUniformValue(variable_location, value.data.toFloat());
break;
case NodeInput::kVec2:
if (corresponding_input && corresponding_input->IsArray()) {
/*if (corresponding_input && corresponding_input->IsArray()) {
QVector<NodeValue> nv = value.value< QVector<NodeValue> >();
QVector<QVector2D> a(nv.size());
@@ -374,41 +330,42 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
shader->setUniformValue(count_location, a.size());
}
} else {
shader->setUniformValue(variable_location, value.value<QVector2D>());
}
}*/
shader->setUniformValue(variable_location, value.data.value<QVector2D>());
break;
case NodeInput::kVec3:
shader->setUniformValue(variable_location, value.value<QVector3D>());
shader->setUniformValue(variable_location, value.data.value<QVector3D>());
break;
case NodeInput::kVec4:
shader->setUniformValue(variable_location, value.value<QVector4D>());
shader->setUniformValue(variable_location, value.data.value<QVector4D>());
break;
case NodeInput::kMatrix:
shader->setUniformValue(variable_location, value.value<QMatrix4x4>());
shader->setUniformValue(variable_location, value.data.value<QMatrix4x4>());
break;
case NodeInput::kCombo:
shader->setUniformValue(variable_location, value.value<int>());
shader->setUniformValue(variable_location, value.data.value<int>());
break;
case NodeInput::kColor:
{
Color color = value.value<Color>();
Color color = value.data.value<Color>();
shader->setUniformValue(variable_location, color.red(), color.green(), color.blue(), color.alpha());
break;
}
case NodeInput::kBoolean:
shader->setUniformValue(variable_location, value.toBool());
shader->setUniformValue(variable_location, value.data.toBool());
break;
case NodeInput::kBuffer:
case NodeInput::kTexture:
{
TexturePtr texture = value.value<TexturePtr>();
TexturePtr texture = value.data.value<TexturePtr>();
// Set value to bound texture
shader->setUniformValue(variable_location, textures_to_bind.size());
// If this texture binding is the iterative input, set it here
if (corresponding_input && corresponding_input == job.GetIterativeInput()) {
if (it.key() == job.GetIterativeInput()) {
iterative_input = textures_to_bind.size();
}
@@ -434,8 +391,8 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
// Adjust virtual width by pixel aspect if necessary
if (texture->params().pixel_aspect_ratio() != 1
|| params.pixel_aspect_ratio() != 1) {
double relative_pixel_aspect = texture->params().pixel_aspect_ratio().toDouble() / params.pixel_aspect_ratio().toDouble();
|| destination_params.pixel_aspect_ratio() != 1) {
double relative_pixel_aspect = texture->params().pixel_aspect_ratio().toDouble() / destination_params.pixel_aspect_ratio().toDouble();
adjusted_width = qRound(static_cast<double>(adjusted_width) * relative_pixel_aspect);
}
@@ -466,32 +423,13 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
}
}
// Provide some standard args
// Set ove_resolution to the destination to the "logical" resolution of the destination
shader->setUniformValue("ove_resolution",
static_cast<GLfloat>(params.width()),
static_cast<GLfloat>(params.height()));
static_cast<GLfloat>(destination_params.width()),
static_cast<GLfloat>(destination_params.height()));
// Create the output textures
int real_iteration_count;
if (job.GetIterationCount() > 1 && job.GetIterativeInput()) {
real_iteration_count = job.GetIterationCount();
} else {
real_iteration_count = 1;
}
TexturePtr dst_refs[2];
dst_refs[0] = CreateTexture(params);
// If this node requires multiple iterations, get a texture for it too
if (real_iteration_count > 1) {
dst_refs[1] = CreateTexture(params);
}
// Some nodes use multiple iterations for optimization
TexturePtr input_tex, output_tex;
// Set up OpenGL parameters as necessary
functions_->glViewport(0, 0, params.effective_width(), params.effective_height());
// Set the viewport to the "physical" resolution of the destination
functions_->glViewport(0, 0, destination_params.effective_width(), destination_params.effective_height());
// Bind all textures
for (int i=0; i<textures_to_bind.size(); i++) {
@@ -516,30 +454,71 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
functions_->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
frag_vbo_.release();
// Some shaders optimize through multiple iterations which requires ping-ponging textures
// - If there are only two iterations, we can just create one backend texture and then the
// destination can be the second
// - If there are more than two iterations, we need to ping pong back and forth between two
// textures. We can still use the destination as the last iteration, but we'll need textures
// for the iterative process.
int real_iteration_count;
if (job.GetIterationCount() > 1 && !job.GetIterativeInput().isEmpty()) {
real_iteration_count = job.GetIterationCount();
} else {
real_iteration_count = 1;
}
TexturePtr output_tex, input_tex;
if (real_iteration_count > 1) {
// Create one texture to bounce off
output_tex = CreateTexture(destination_params);
if (real_iteration_count > 2) {
// Create a second texture bounce off
input_tex = CreateTexture(destination_params);
}
}
for (int iteration=0; iteration<real_iteration_count; iteration++) {
// Set iteration number
shader->setUniformValue("ove_iteration", iteration);
// Replace iterative input
if (iteration == 0) {
output_tex = dst_refs[0];
if (iteration == real_iteration_count-1) {
// This is the last iteration, draw to the destination
if (destination) {
// If we have a destination texture, draw to it
AttachTextureAsDestination(destination);
} else if (iteration > 0) {
// Otherwise, if we were iterating before, detach texture now
DetachTextureAsDestination();
}
} else {
input_tex = dst_refs[(iteration+1)%2];
output_tex = dst_refs[iteration%2];
// Always draw to output_tex
AttachTextureAsDestination(output_tex.get());
functions_->glActiveTexture(GL_TEXTURE0 + iterative_input);
functions_->glBindTexture(GL_TEXTURE_2D, input_tex->id().value<GLuint>());
PrepareInputTexture(job.GetBilinearFiltering());
if (iteration > 0) {
// If this is not the first iteration, replace the iterative texture with the one we
// last drew
functions_->glActiveTexture(GL_TEXTURE0 + iterative_input);
functions_->glBindTexture(GL_TEXTURE_2D, input_tex->id().value<GLuint>());
PrepareInputTexture(job.GetBilinearFiltering());
}
// Swap so that the next iteration, the texture we draw now will be the input texture next
std::swap(output_tex, input_tex);
}
AttachTextureAsDestination(output_tex.get());
// Blit this texture through this shader
functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3);
}
// Reset framebuffer to default
DetachTextureAsDestination();
if (destination) {
// Reset framebuffer to default if we were drawing to a texture
DetachTextureAsDestination();
// Set metadata for whether this texture has a meaningful alpha channel
destination->set_has_meaningful_alpha((input_textures_have_alpha || job.GetAlphaChannelRequired()));
}
// Release any textures we bound before
for (int i=textures_to_bind.size()-1; i>=0; i--) {
@@ -552,23 +531,9 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j
// Release shader
shader->release();
output_tex->set_has_meaningful_alpha((input_textures_have_alpha || job.GetAlphaChannelRequired()));
return output_tex;
}
void OpenGLRenderer::SetViewport(int width, int height)
{
functions_->glViewport(0, 0, width, height);
}
void OpenGLRenderer::BlitColorManaged(ColorProcessorPtr color_processor, Texture *source, Renderer::Texture* destination)
{
qCritical() << "OpenGLRenderer::BlitColorMangaed is a stub!";
}
void OpenGLRenderer::Blit(Renderer::Texture *source, QVariant shader, Renderer::ShaderUniformMap parameters, Renderer::Texture *destination)
/*void OpenGLRenderer::Blit(Renderer::Texture *source, QVariant shader, Renderer::ShaderUniformMap parameters, Renderer::Texture *destination)
{
QOpenGLShaderProgram* program = Node::ValueToPtr<QOpenGLShaderProgram>(shader);
@@ -594,7 +559,7 @@ void OpenGLRenderer::Blit(Renderer::Texture *source, QVariant shader, Renderer::
if (destination) {
DetachTextureAsDestination();
}
}
}*/
GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format)
{
+9 -15
View File
@@ -51,10 +51,6 @@ public slots:
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
virtual void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture) override;
virtual void DetachTextureAsDestination() override;
virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) override;
virtual void DestroyNativeTexture(QVariant texture) override;
@@ -67,21 +63,21 @@ public slots:
virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) override;
virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::VideoParams params) override;
virtual void SetViewport(int width, int height) override;
virtual void BlitColorManaged(OLIVE_NAMESPACE::ColorProcessorPtr color_processor, OLIVE_NAMESPACE::Renderer::Texture* source, OLIVE_NAMESPACE::Renderer::Texture *destination = nullptr) override;
virtual void Blit(OLIVE_NAMESPACE::Renderer::Texture* source, QVariant shader, OLIVE_NAMESPACE::Renderer::ShaderUniformMap parameters, OLIVE_NAMESPACE::Renderer::Texture* destination = nullptr) override;
protected slots:
virtual void Blit(QVariant shader,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::Renderer::Texture* destination,
OLIVE_NAMESPACE::VideoParams destination_params) override;
private:
static GLint GetInternalFormat(PixelFormat::Format format);
static GLenum GetPixelType(PixelFormat::Format format);
void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture);
void DetachTextureAsDestination();
void PrepareInputTexture(bool bilinear);
QOpenGLContext* context_;
@@ -98,8 +94,6 @@ private:
GLuint framebuffer_;
QHash<QString, QOpenGLShaderProgram*> shader_cache_;
};
OLIVE_NAMESPACE_EXIT
+94
View File
@@ -20,6 +20,13 @@
#include "renderer.h"
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#include <QFloat16>
#include "render/colormanager.h"
OLIVE_NAMESPACE_ENTER
Renderer::Renderer(QObject *parent) :
@@ -39,4 +46,91 @@ Renderer::TexturePtr Renderer::CreateTexture(const VideoParams &param, void *dat
return std::make_shared<Texture>(this, v, param);
}
// copied from source code to OCIODisplay
/*const int OCIO_LUT3D_EDGE_SIZE = 64;
const int OCIO_LUT3D_PIXEL_COUNT = OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE;
const int OCIO_LUT3D_ENTRY_COUNT = 3 * OCIO_LUT3D_PIXEL_COUNT;
const int OCIO_LUT3D_ENTRY_COUNT_WITH_ALPHA = 4 * OCIO_LUT3D_PIXEL_COUNT;
const int OCIO_LUT2D_EDGE_SIZE = 512;*/
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture *destination)
{
/*ColorContext color_ctx;
if (color_cache_.contains(color_processor->id())) {
color_ctx = color_cache_.value(color_processor->id());
} else {
// Generate OCIO color context
// Generate OCIO shader descriptor
const char* ocio_func_name = "OCIODisplay";
OCIO::GpuShaderDesc shader_desc;
shader_desc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
shader_desc.setFunctionName(ocio_func_name);
shader_desc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE);
// Generate LUT
QVector<float> lut_data(OCIO_LUT3D_ENTRY_COUNT);
color_processor->GetProcessor()->getGpuLut3D(lut_data.data(), shader_desc);
// Convert to half float RGBA
QVector<qfloat16> texture_ready_lut_data(OCIO_LUT3D_ENTRY_COUNT_WITH_ALPHA);
for (int i=0; i<OCIO_LUT3D_PIXEL_COUNT; i++) {
texture_ready_lut_data[i*kRGBAChannels+0] = lut_data[i*kRGBChannels+0];
texture_ready_lut_data[i*kRGBAChannels+1] = lut_data[i*kRGBChannels+1];
texture_ready_lut_data[i*kRGBAChannels+2] = lut_data[i*kRGBChannels+2];
texture_ready_lut_data[i*kRGBAChannels+3] = 1.0f;
}
// Create LUT texture
color_ctx.lut = CreateTexture(VideoParams(OCIO_LUT2D_EDGE_SIZE, OCIO_LUT2D_EDGE_SIZE, PixelFormat::PIX_FMT_RGBA32F),
texture_ready_lut_data.data());
// Create shader
QString frag_code;
frag_code.append(QStringLiteral("sampler2D texture;\n"
"sampler2D lut;\n"
"\n"
"vec3 LUTLookup(sampler2D lut3d, vec3 in_coord)\n"
"{\n"
" return texture2D(lut3d, vec2());\n"
"}\n"
"\n"));
// Correct code for our GLSL set up
QString ocio_code = color_processor->GetProcessor()->getGpuShaderText(shader_desc);
ocio_code.replace(QStringLiteral("texture3D"), QStringLiteral("texture2D"));
ocio_code.replace(QStringLiteral("sampler3D"), QStringLiteral("sampler2D"));
qDebug() << frag_code;
//qDebug() << "FIXME: GPU doesn't handle associated alpha yet";
}*/
qDebug() << "BlitColorManaged is a partial stub";
QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert")));
ShaderJob job;
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture));
BlitToTexture(shader, job, destination);
}
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params)
{
qDebug() << "BlitColorManaged is a partial stub";
QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert")));
ShaderJob job;
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture));
Blit(shader, job, params);
}
OLIVE_NAMESPACE_EXIT
+25 -18
View File
@@ -121,12 +121,22 @@ public:
TexturePtr CreateTexture(const VideoParams& param, void* data = nullptr, int linesize = 0);
struct ShaderValue {
QVariant data;
NodeParam::DataType type;
};
void BlitToTexture(QVariant shader,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::Renderer::Texture* destination)
{
Blit(shader, job, destination, destination->params());
}
using ShaderUniformMap = QHash<QString, ShaderValue>;
void Blit(QVariant shader,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::VideoParams params)
{
Blit(shader, job, nullptr, params);
}
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture* destination);
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params);
public slots:
virtual void PostInit() = 0;
@@ -135,10 +145,6 @@ public slots:
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) = 0;
virtual void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture) = 0;
virtual void DetachTextureAsDestination() = 0;
virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) = 0;
virtual void DestroyNativeTexture(QVariant texture) = 0;
@@ -151,18 +157,19 @@ public slots:
virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) = 0;
virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::VideoParams params) = 0;
virtual void SetViewport(int width, int height) = 0;
virtual void BlitColorManaged(OLIVE_NAMESPACE::ColorProcessorPtr color_processor, OLIVE_NAMESPACE::Renderer::Texture* source, OLIVE_NAMESPACE::Renderer::Texture *destination = nullptr) = 0;
virtual void Blit(OLIVE_NAMESPACE::Renderer::Texture* source, QVariant shader, OLIVE_NAMESPACE::Renderer::ShaderUniformMap parameters, OLIVE_NAMESPACE::Renderer::Texture* destination = nullptr) = 0;
protected slots:
virtual void Blit(QVariant shader,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::Renderer::Texture* destination,
OLIVE_NAMESPACE::VideoParams destination_params) = 0;
private:
struct ColorContext {
QVariant shader;
TexturePtr lut;
};
QHash<QString, ColorContext> color_cache_;
};
+4 -41
View File
@@ -76,17 +76,6 @@ void RendererThreadWrapper::ClearDestination(double r, double g, double b, doubl
Q_ARG(double, a));
}
void RendererThreadWrapper::AttachTextureAsDestination(Renderer::Texture *texture)
{
QMetaObject::invokeMethod(inner_, "AttachTextureAsDestination", Qt::BlockingQueuedConnection,
OLIVE_NS_ARG(Renderer::Texture*, texture));
}
void RendererThreadWrapper::DetachTextureAsDestination()
{
QMetaObject::invokeMethod(inner_, "DetachTextureAsDestination", Qt::BlockingQueuedConnection);
}
QVariant RendererThreadWrapper::CreateNativeTexture(VideoParams param, void *data, int linesize)
{
QVariant v;
@@ -139,41 +128,15 @@ void RendererThreadWrapper::DownloadFromTexture(Renderer::Texture *texture, void
Q_ARG(int, linesize));
}
Renderer::TexturePtr RendererThreadWrapper::ProcessShader(const Node *node, ShaderJob job, VideoParams params)
void RendererThreadWrapper::Blit(QVariant shader, ShaderJob job, Renderer::Texture *destination, VideoParams destination_params)
{
Renderer::TexturePtr tex;
QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection,
OLIVE_NS_RETURN_ARG(Renderer::TexturePtr, tex),
OLIVE_NS_CONST_ARG(Node*, node),
OLIVE_NS_ARG(ShaderJob, job),
OLIVE_NS_ARG(VideoParams, params));
return tex;
}
void RendererThreadWrapper::SetViewport(int width, int height)
{
QMetaObject::invokeMethod(inner_, "SetViewport", Qt::BlockingQueuedConnection,
Q_ARG(int, width),
Q_ARG(int, height));
}
void RendererThreadWrapper::BlitColorManaged(ColorProcessorPtr color_processor, Renderer::Texture *source, Renderer::Texture *destination)
{
QMetaObject::invokeMethod(inner_, "BlitColorManaged", Qt::BlockingQueuedConnection,
OLIVE_NS_ARG(ColorProcessorPtr, color_processor),
OLIVE_NS_ARG(Renderer::Texture*, source),
OLIVE_NS_ARG(Renderer::Texture*, destination));
}
void RendererThreadWrapper::Blit(Renderer::Texture *source, QVariant shader, Renderer::ShaderUniformMap parameters, Renderer::Texture *destination)
{
QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection,
OLIVE_NS_ARG(Renderer::Texture*, source),
Q_ARG(QVariant, shader),
Q_ARG(Renderer::ShaderUniformMap, parameters),
OLIVE_NS_ARG(Renderer::Texture*, destination));
OLIVE_NS_ARG(ShaderJob, job),
OLIVE_NS_ARG(Renderer::Texture*, destination),
OLIVE_NS_ARG(VideoParams, destination_params));
}
OLIVE_NAMESPACE_EXIT
+5 -13
View File
@@ -47,10 +47,6 @@ public slots:
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
virtual void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture) override;
virtual void DetachTextureAsDestination() override;
virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) override;
virtual void DestroyNativeTexture(QVariant texture) override;
@@ -63,15 +59,11 @@ public slots:
virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) override;
virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::VideoParams params) override;
virtual void SetViewport(int width, int height) override;
virtual void BlitColorManaged(OLIVE_NAMESPACE::ColorProcessorPtr color_processor, OLIVE_NAMESPACE::Renderer::Texture* source, OLIVE_NAMESPACE::Renderer::Texture *destination = nullptr) override;
virtual void Blit(OLIVE_NAMESPACE::Renderer::Texture* source, QVariant shader, OLIVE_NAMESPACE::Renderer::ShaderUniformMap parameters, OLIVE_NAMESPACE::Renderer::Texture* destination = nullptr) override;
protected slots:
virtual void Blit(QVariant shader,
OLIVE_NAMESPACE::ShaderJob job,
OLIVE_NAMESPACE::Renderer::Texture* destination,
OLIVE_NAMESPACE::VideoParams destination_params) override;
private:
Renderer* inner_;
+11
View File
@@ -54,6 +54,8 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const
output.toUtf8());
}
id_ = GenerateID(config, input, transform);
}
void ColorProcessor::ConvertFrame(Frame *f)
@@ -75,6 +77,15 @@ Color ColorProcessor::ConvertColor(Color in)
return in;
}
QString ColorProcessor::GenerateID(ColorManager *config, const QString &input, const ColorTransform &transform)
{
return QStringLiteral("%1:%2:%3:%4:%5").arg(config->GetConfigFilename(),
input,
transform.display(),
transform.view(),
transform.look());
}
ColorProcessorPtr ColorProcessor::Create(ColorManager *config, const QString& input, const ColorTransform &transform)
{
return std::make_shared<ColorProcessor>(config, input, transform);
+9
View File
@@ -53,9 +53,18 @@ public:
Color ConvertColor(Color in);
const QString& id() const
{
return id_;
}
static QString GenerateID(ColorManager* config, const QString& input, const ColorTransform& dest_space);
private:
OCIO::ConstProcessorRcPtr processor_;
QString id_;
};
using ColorProcessorChain = QList<ColorProcessorPtr>;
-1
View File
@@ -22,7 +22,6 @@
#define COLORTRANSFORM_H
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#include <QString>
+4 -3
View File
@@ -19,7 +19,8 @@ PreviewAutoCacher::PreviewAutoCacher() :
last_update_time_(0),
ignore_next_mouse_button_(false),
video_params_changed_(false),
audio_params_changed_(false)
audio_params_changed_(false),
color_manager_(nullptr)
{
// Set default autocache range
SetPlayhead(rational());
@@ -582,7 +583,7 @@ void PreviewAutoCacher::TryRender()
single_frame_render_->Start();
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_,
static_cast<Sequence*>(viewer_node_->parent())->project()->color_manager(),
color_manager_,
single_frame_render_->property("time").value<rational>(),
RenderMode::kOffline, true));
@@ -624,7 +625,7 @@ void PreviewAutoCacher::RequeueFrames()
connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::VideoRendered);
video_tasks_.insert(watcher, hash);
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_,
static_cast<Sequence*>(viewer_node_->parent())->project()->color_manager(),
color_manager_,
t, RenderMode::kOffline, false));
}
}
+8
View File
@@ -6,6 +6,7 @@
#include "config/config.h"
#include "node/node.h"
#include "node/output/viewer/viewer.h"
#include "render/colormanager.h"
#include "threading/threadticketwatcher.h"
OLIVE_NAMESPACE_ENTER
@@ -83,6 +84,11 @@ public:
void ClearAudioQueue(bool wait = false);
void ClearVideoDownloadQueue(bool wait = false);
void SetColorManager(ColorManager* manager)
{
color_manager_ = manager;
}
public slots:
/**
* @brief Main handler for when the NodeGraph changes
@@ -148,6 +154,8 @@ private:
bool audio_params_changed_;
ColorManager* color_manager_;
private slots:
/**
* @brief Handler for when the NodeGraph reports a video change over a certain time range
@@ -18,15 +18,16 @@
***/
#ifndef DECODERCACHE_H
#define DECODERCACHE_H
#ifndef RENDERCACHE_H
#define RENDERCACHE_H
#include "codec/decoder.h"
#include "project/item/footage/stream.h"
OLIVE_NAMESPACE_ENTER
class DecoderCache : public QHash<Stream*, DecoderPtr>
template <typename K, typename V>
class RenderCache : public QHash<K, V>
{
public:
QMutex *mutex()
@@ -39,6 +40,9 @@ private:
};
using DecoderCache = RenderCache<Stream*, DecoderPtr>;
using ShaderCache = RenderCache<QString, QVariant>;
OLIVE_NAMESPACE_EXIT
#endif // DECODERCACHE_H
#endif // RENDERCACHE_H
+3 -1
View File
@@ -55,6 +55,7 @@ RenderManager::RenderManager(QObject *parent) :
still_cache_ = new StillImageCache();
decoder_cache_ = new DecoderCache();
shader_cache_ = new ShaderCache();
} else {
qCritical() << "Tried to initialize unknown graphics backend";
still_cache_ = nullptr;
@@ -64,6 +65,7 @@ RenderManager::RenderManager(QObject *parent) :
RenderManager::~RenderManager()
{
delete shader_cache_;
delete decoder_cache_;
delete still_cache_;
@@ -162,7 +164,7 @@ RenderTicketPtr RenderManager::SaveFrameToCache(FrameHashCache *cache, FramePtr
void RenderManager::RunTicket(RenderTicketPtr ticket) const
{
RenderProcessor::Process(ticket, context_, still_cache_, decoder_cache_);
RenderProcessor::Process(ticket, context_, still_cache_, decoder_cache_, shader_cache_);
}
OLIVE_NAMESPACE_EXIT
+3 -1
View File
@@ -26,11 +26,11 @@
#include "config/config.h"
#include "colorprocessorcache.h"
#include "dialog/rendercancel/rendercancel.h"
#include "decodercache.h"
#include "node/graph.h"
#include "node/output/viewer/viewer.h"
#include "node/traverser.h"
#include "render/backend/renderer.h"
#include "rendercache.h"
#include "stillimagecache.h"
#include "threading/threadpool.h"
@@ -127,6 +127,8 @@ private:
DecoderCache* decoder_cache_;
ShaderCache* shader_cache_;
};
OLIVE_NAMESPACE_EXIT
+32 -9
View File
@@ -29,11 +29,12 @@
OLIVE_NAMESPACE_ENTER
RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache) :
RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache *shader_cache) :
ticket_(ticket),
render_ctx_(render_ctx),
still_image_cache_(still_image_cache),
decoder_cache_(decoder_cache)
decoder_cache_(decoder_cache),
shader_cache_(shader_cache)
{
}
@@ -137,9 +138,9 @@ DecoderPtr RenderProcessor::ResolveDecoderFromInput(StreamPtr stream)
return decoder;
}
void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache *still_image_cache, DecoderCache *decoder_cache)
void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache *still_image_cache, DecoderCache *decoder_cache, ShaderCache *shader_cache)
{
RenderProcessor p(ticket, render_ctx, still_image_cache, decoder_cache);
RenderProcessor p(ticket, render_ctx, still_image_cache, decoder_cache, shader_cache);
p.Run();
}
@@ -228,9 +229,10 @@ QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &
// to optimize such a situation
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(stream);
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
StillImageCache::Entry want_entry = {nullptr,
stream,
video_stream->get_colorspace_match_string(),
ColorProcessor::GenerateID(Node::ValueToPtr<ColorManager>(ticket_->property("colormanager")), video_stream->colorspace(), ColorTransform(OCIO::ROLE_SCENE_LINEAR)),
video_stream->premultiplied_alpha(),
video_params.divider(),
(video_stream->video_type() == VideoStream::kVideoTypeStill) ? 0 : input_time};
@@ -293,14 +295,14 @@ QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &
managed_params.set_format(video_params.format());
value = render_ctx_->CreateTexture(managed_params);
// FIXME: Accessing video_stream->colorspace()
qDebug() << "FIXME: Accessing video_stream->colorspace() may cause race conditions";
ColorManager* color_manager = video_stream->footage()->project()->color_manager();
ColorProcessorPtr processor = ColorProcessor::Create(color_manager,
video_stream->colorspace(),
ColorTransform(OCIO::ROLE_SCENE_LINEAR));
render_ctx_->BlitColorManaged(processor, unmanaged_texture.get(), value.get());
render_ctx_->BlitColorManaged(processor, unmanaged_texture, value.get());
still_image_cache_->mutex()->lock();
@@ -341,9 +343,30 @@ QVariant RenderProcessor::ProcessShader(const Node *node, const TimeRange &range
{
Q_UNUSED(range)
QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), job.GetShaderID());
QMutexLocker locker(shader_cache_->mutex());
QVariant shader = shader_cache_->value(full_shader_id);
if (shader.isNull()) {
// Since we have shader code, compile it now
shader = render_ctx_->CreateNativeShader(node->GetShaderCode(job.GetShaderID()));
if (shader.isNull()) {
// Couldn't find or build the shader required
return QVariant();
}
}
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
return QVariant::fromValue(render_ctx_->ProcessShader(node, job, video_params));
Renderer::TexturePtr destination = render_ctx_->CreateTexture(video_params);
// Run shader
render_ctx_->BlitToTexture(shader, job, destination.get());
return QVariant::fromValue(destination);
}
QVariant RenderProcessor::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job)
@@ -372,7 +395,7 @@ QVariant RenderProcessor::ProcessSamples(const Node *node, const TimeRange &rang
if (corresponding_input) {
value = ProcessInput(corresponding_input, TimeRange(this_sample_time, this_sample_time));
} else {
value.Push(j.value());
value.Push(j.value(), node);
}
value_db.Insert(j.key(), value);
+5 -3
View File
@@ -21,9 +21,9 @@
#ifndef RENDERPROCESSOR_H
#define RENDERPROCESSOR_H
#include "decodercache.h"
#include "node/traverser.h"
#include "render/backend/renderer.h"
#include "rendercache.h"
#include "stillimagecache.h"
#include "threading/threadticket.h"
@@ -32,7 +32,7 @@ OLIVE_NAMESPACE_ENTER
class RenderProcessor : public NodeTraverser
{
public:
static void Process(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache);
static void Process(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache* shader_cache);
struct RenderedWaveform {
const TrackOutput* track;
@@ -56,7 +56,7 @@ protected:
virtual QVariant GetCachedFrame(const Node *node, const rational &time) override;
private:
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache);
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache* shader_cache);
void Run();
@@ -70,6 +70,8 @@ private:
DecoderCache* decoder_cache_;
ShaderCache* shader_cache_;
};
OLIVE_NAMESPACE_EXIT
+43 -14
View File
@@ -2,56 +2,73 @@
#define SHADERINFO_H
#include "codec/samplebuffer.h"
#include "common/filefunctions.h"
#include "node/input.h"
#include "node/inputarray.h"
#include "node/value.h"
OLIVE_NAMESPACE_ENTER
using NodeValueMap = QHash<QString, NodeValue>;
using NodeValueMap = QHash<QString, ShaderValue>;
class AcceleratedJob {
public:
AcceleratedJob() = default;
NodeValue GetValue(NodeInput* input) const
ShaderValue GetValue(NodeInput* input) const
{
return value_map_.value(input->id());
}
NodeValue GetValue(const QString& input) const
ShaderValue GetValue(const QString& input) const
{
return value_map_.value(input);
}
void InsertValue(NodeInput* input, NodeValueDatabase& value)
{
ShaderValue shader_val;
shader_val.type = input->data_type();
shader_val.array = input->IsArray();
if (input->IsArray()) {
NodeInputArray* array = static_cast<NodeInputArray*>(input);
QVector<NodeValue> values(array->GetSize());
QVector<QVariant> values(array->GetSize());
for (int j=0;j<array->GetSize();j++) {
NodeInput* subparam = array->At(j);
values[j] = value[subparam].TakeWithMeta(subparam->data_type());
values[j] = value[subparam].Take(subparam->data_type());
}
InsertValue(input->id(), NodeValue(NodeParam::kVec2, QVariant::fromValue(values), input->parentNode()));
shader_val.data = QVariant::fromValue(values);
} else {
InsertValue(input->id(), value[input].TakeWithMeta(input->data_type()));
NodeValue node_val = value[input].TakeWithMeta(input->data_type());
shader_val.data = node_val.data();
shader_val.tag = node_val.tag();
}
InsertValue(input->id(), shader_val);
}
void InsertValue(const QString& input, const NodeValue& value)
void InsertValue(const QString& input, const ShaderValue& value)
{
value_map_.insert(input, value);
}
void InsertValue(NodeInput* input, const NodeValue& value)
void InsertValue(NodeInput* input, const ShaderValue& value)
{
value_map_.insert(input->id(), value);
}
void InsertValue(NodeInput* input, const NodeValue& value)
{
ShaderValue s(value.data(), value.type());
s.tag = value.tag();
value_map_.insert(input->id(), s);
}
const NodeValueMap &GetValues() const
{
return value_map_;
@@ -127,15 +144,20 @@ public:
const QString& GetShaderID() const
{
return id_;
return shader_id_;
}
void SetShaderID(const QString& id)
{
id_ = id;
shader_id_ = id;
}
void SetIterations(int iterations, NodeInput* iterative_input)
{
SetIterations(iterations, iterative_input->id());
}
void SetIterations(int iterations, const QString& iterative_input)
{
iterations_ = iterations;
iterative_input_ = iterative_input;
@@ -146,7 +168,7 @@ public:
return iterations_;
}
NodeInput* GetIterativeInput() const
const QString& GetIterativeInput() const
{
return iterative_input_;
}
@@ -162,11 +184,11 @@ public:
}
private:
QString id_;
QString shader_id_;
int iterations_;
NodeInput* iterative_input_;
QString iterative_input_;
bool bilinear_;
@@ -178,6 +200,13 @@ public:
frag_code_(frag_code),
vert_code_(vert_code)
{
if (frag_code_.isEmpty()) {
frag_code_ = FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.frag"));
}
if (vert_code_.isEmpty()) {
vert_code_ = FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.vert"));
}
}
const QString& frag_code() const
+53
View File
@@ -0,0 +1,53 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef SHADERVALUE_H
#define SHADERVALUE_H
#include "node/param.h"
OLIVE_NAMESPACE_ENTER
struct ShaderValue
{
ShaderValue()
{
type = NodeParam::kNone;
array = false;
}
ShaderValue(QVariant data_in, NodeParam::DataType type_in, bool array_in = false)
{
data = data_in;
type = type_in;
array = array_in;
}
NodeParam::DataType type;
QVariant data;
bool array;
QString tag;
};
OLIVE_NAMESPACE_EXIT
#endif // SHADERVALUE_H