large scale renderer rework
- Abstracts all OpenGL functionality including UI objects - Cleans up several rendering codepaths - Improves threading functionality - Removes old code and problematic functions
This commit is contained in:
@@ -75,7 +75,7 @@ SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidg
|
||||
preview_layout->addWidget(preview_resolution_label_, row, 2);
|
||||
row++;
|
||||
preview_layout->addWidget(new QLabel(tr("Format:")), row, 0);
|
||||
preview_format_field_ = new PixelFormatComboBox(true, true);
|
||||
preview_format_field_ = new PixelFormatComboBox(true);
|
||||
preview_layout->addWidget(preview_format_field_, row, 1, 1, 2);
|
||||
layout->addWidget(preview_group);
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ OpenGLRenderer::OpenGLRenderer(QObject* parent) :
|
||||
|
||||
OpenGLRenderer::~OpenGLRenderer()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void OpenGLRenderer::Init(QOpenGLContext *existing_ctx)
|
||||
@@ -97,13 +98,14 @@ bool OpenGLRenderer::Init()
|
||||
void OpenGLRenderer::PostInit()
|
||||
{
|
||||
// Make context current on that surface
|
||||
if (!context_->makeCurrent(&surface_)) {
|
||||
if (context_->parent() == this && !context_->makeCurrent(&surface_)) {
|
||||
qCritical() << "Failed to makeCurrent() on offscreen surface in thread" << thread();
|
||||
return;
|
||||
}
|
||||
|
||||
// Store OpenGL functions instance
|
||||
functions_ = context_->functions();
|
||||
|
||||
// Store OpenGL functions instance
|
||||
functions_->glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
// Set up framebuffer used for various things
|
||||
@@ -127,6 +129,11 @@ void OpenGLRenderer::PostInit()
|
||||
|
||||
void OpenGLRenderer::Destroy()
|
||||
{
|
||||
if (context_) {
|
||||
// Delete buffers
|
||||
vert_vbo_.destroy();
|
||||
frag_vbo_.destroy();
|
||||
|
||||
// Delete vertex array object
|
||||
vao_.destroy();
|
||||
|
||||
@@ -148,8 +155,32 @@ void OpenGLRenderer::Destroy()
|
||||
surface_.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVariant OpenGLRenderer::CreateNativeTexture(const VideoParams &p, void *data, int linesize)
|
||||
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);
|
||||
|
||||
SetViewport(texture->width(), texture->height());
|
||||
}
|
||||
|
||||
void OpenGLRenderer::DetachTextureAsDestination()
|
||||
{
|
||||
functions_->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
QVariant OpenGLRenderer::CreateNativeTexture(VideoParams p, void *data, int linesize)
|
||||
{
|
||||
GLuint texture;
|
||||
functions_->glGenTextures(1, &texture);
|
||||
@@ -157,7 +188,7 @@ QVariant OpenGLRenderer::CreateNativeTexture(const VideoParams &p, void *data, i
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
||||
|
||||
functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(p.format()),
|
||||
p.width(), p.height(), 0, GetPixelFormat(p.format()),
|
||||
p.width(), p.height(), 0, GL_RGBA,
|
||||
GetPixelType(p.format()), data);
|
||||
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
@@ -171,6 +202,37 @@ void OpenGLRenderer::DestroyNativeTexture(QVariant texture)
|
||||
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>();
|
||||
@@ -186,7 +248,7 @@ void OpenGLRenderer::UploadToTexture(Texture *texture, void *data, int linesize)
|
||||
|
||||
functions_->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
||||
p.effective_width(), p.effective_height(),
|
||||
GetPixelFormat(p.format()), GetPixelType(p.format()),
|
||||
GL_RGBA, GetPixelType(p.format()),
|
||||
data);
|
||||
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
@@ -210,7 +272,7 @@ void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int lines
|
||||
0,
|
||||
p.width(),
|
||||
p.height(),
|
||||
GetPixelFormat(p.format()),
|
||||
GL_RGBA,
|
||||
GetPixelType(p.format()),
|
||||
data);
|
||||
|
||||
@@ -219,7 +281,7 @@ void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int lines
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
|
||||
}
|
||||
|
||||
Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job, const VideoParams ¶ms)
|
||||
Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob job, VideoParams params)
|
||||
{
|
||||
// If this node is iterative, we'll pick up which input here
|
||||
GLuint iterative_input = 0;
|
||||
@@ -342,12 +404,6 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
||||
{
|
||||
TexturePtr texture = value.value<TexturePtr>();
|
||||
|
||||
if (texture) {
|
||||
if (PixelFormat::FormatHasAlphaChannel(texture->format())) {
|
||||
input_textures_have_alpha = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Set value to bound texture
|
||||
shader->setUniformValue(variable_location, textures_to_bind.size());
|
||||
|
||||
@@ -359,6 +415,10 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
||||
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) {
|
||||
@@ -412,17 +472,6 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
||||
static_cast<GLfloat>(params.height()));
|
||||
|
||||
// Create the output textures
|
||||
PixelFormat::Format output_format = (input_textures_have_alpha || job.GetAlphaChannelRequired())
|
||||
? PixelFormat::GetFormatWithAlphaChannel(params.format())
|
||||
: PixelFormat::GetFormatWithoutAlphaChannel(params.format());
|
||||
VideoParams output_params(params.width(),
|
||||
params.height(),
|
||||
params.time_base(),
|
||||
output_format,
|
||||
params.pixel_aspect_ratio(),
|
||||
params.interlacing(),
|
||||
params.divider());
|
||||
|
||||
int real_iteration_count;
|
||||
if (job.GetIterationCount() > 1 && job.GetIterativeInput()) {
|
||||
real_iteration_count = job.GetIterationCount();
|
||||
@@ -431,11 +480,11 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
||||
}
|
||||
|
||||
TexturePtr dst_refs[2];
|
||||
dst_refs[0] = CreateTexture(output_params);
|
||||
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(output_params);
|
||||
dst_refs[1] = CreateTexture(params);
|
||||
}
|
||||
|
||||
// Some nodes use multiple iterations for optimization
|
||||
@@ -483,19 +532,14 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
||||
PrepareInputTexture(job.GetBilinearFiltering());
|
||||
}
|
||||
|
||||
functions_->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
|
||||
functions_->glFramebufferTexture2D(GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D,
|
||||
output_tex->id().value<GLuint>(),
|
||||
0);
|
||||
AttachTextureAsDestination(output_tex.get());
|
||||
|
||||
// Blit this texture through this shader
|
||||
functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3);
|
||||
}
|
||||
|
||||
// Reset framebuffer to default
|
||||
functions_->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
DetachTextureAsDestination();
|
||||
|
||||
// Release any textures we bound before
|
||||
for (int i=textures_to_bind.size()-1; i>=0; i--) {
|
||||
@@ -509,26 +553,58 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, const TimeR
|
||||
// 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)
|
||||
{
|
||||
QOpenGLShaderProgram* program = Node::ValueToPtr<QOpenGLShaderProgram>(shader);
|
||||
|
||||
if (!program) {
|
||||
qCritical() << "Attempted to blit with a null shader";
|
||||
return;
|
||||
}
|
||||
|
||||
if (destination) {
|
||||
AttachTextureAsDestination(destination);
|
||||
}
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, source->id().value<GLuint>());
|
||||
|
||||
program->bind();
|
||||
|
||||
qCritical() << "OpenGLRenderer::Blit is a stub!";
|
||||
|
||||
program->release();
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
if (destination) {
|
||||
DetachTextureAsDestination();
|
||||
}
|
||||
}
|
||||
|
||||
GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format)
|
||||
{
|
||||
switch (format) {
|
||||
case PixelFormat::PIX_FMT_RGB8:
|
||||
return GL_RGB8;
|
||||
case PixelFormat::PIX_FMT_RGBA8:
|
||||
return GL_RGBA8;
|
||||
case PixelFormat::PIX_FMT_RGB16U:
|
||||
return GL_RGB16;
|
||||
case PixelFormat::PIX_FMT_RGBA16U:
|
||||
return GL_RGBA16;
|
||||
case PixelFormat::PIX_FMT_RGB16F:
|
||||
return GL_RGB16F;
|
||||
case PixelFormat::PIX_FMT_RGBA16F:
|
||||
return GL_RGBA16F;
|
||||
case PixelFormat::PIX_FMT_RGB32F:
|
||||
return GL_RGB32F;
|
||||
case PixelFormat::PIX_FMT_RGBA32F:
|
||||
return GL_RGBA32F;
|
||||
|
||||
@@ -540,28 +616,15 @@ GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format)
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
GLenum OpenGLRenderer::GetPixelFormat(PixelFormat::Format format)
|
||||
{
|
||||
if (PixelFormat::FormatHasAlphaChannel(format)) {
|
||||
return GL_RGBA;
|
||||
} else {
|
||||
return GL_RGB;
|
||||
}
|
||||
}
|
||||
|
||||
GLenum OpenGLRenderer::GetPixelType(PixelFormat::Format format)
|
||||
{
|
||||
switch (format) {
|
||||
case PixelFormat::PIX_FMT_RGB8:
|
||||
case PixelFormat::PIX_FMT_RGBA8:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
case PixelFormat::PIX_FMT_RGB16U:
|
||||
case PixelFormat::PIX_FMT_RGBA16U:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
case PixelFormat::PIX_FMT_RGB16F:
|
||||
case PixelFormat::PIX_FMT_RGBA16F:
|
||||
return GL_HALF_FLOAT;
|
||||
case PixelFormat::PIX_FMT_RGB32F:
|
||||
case PixelFormat::PIX_FMT_RGBA32F:
|
||||
return GL_FLOAT;
|
||||
|
||||
|
||||
@@ -49,26 +49,37 @@ public slots:
|
||||
|
||||
virtual void Destroy() override;
|
||||
|
||||
virtual QVariant CreateNativeTexture(const VideoParams& p, void* data = nullptr, int linesize = 0) override;
|
||||
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;
|
||||
|
||||
virtual void UploadToTexture(Texture* texture, void* data, int linesize) override;
|
||||
virtual QVariant CreateNativeShader(OLIVE_NAMESPACE::ShaderCode code) override;
|
||||
|
||||
virtual void DownloadFromTexture(Texture* texture, void* data, int linesize) 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;
|
||||
|
||||
virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node,
|
||||
const OLIVE_NAMESPACE::TimeRange &range,
|
||||
const OLIVE_NAMESPACE::ShaderJob &job,
|
||||
const OLIVE_NAMESPACE::VideoParams ¶ms) override;
|
||||
OLIVE_NAMESPACE::ShaderJob job,
|
||||
OLIVE_NAMESPACE::VideoParams params) override;
|
||||
|
||||
virtual TexturePtr TransformColor(Texture* texture, OLIVE_NAMESPACE::ColorProcessorPtr processor) 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;
|
||||
|
||||
private:
|
||||
static GLint GetInternalFormat(PixelFormat::Format format);
|
||||
|
||||
static GLenum GetPixelFormat(PixelFormat::Format format);
|
||||
|
||||
static GLenum GetPixelType(PixelFormat::Format format);
|
||||
|
||||
void PrepareInputTexture(bool bilinear);
|
||||
@@ -93,6 +104,4 @@ private:
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::OpenGLRenderer::TexturePtr);
|
||||
|
||||
#endif // OPENGLCONTEXT_H
|
||||
|
||||
@@ -38,8 +38,6 @@ class Renderer : public QObject
|
||||
public:
|
||||
Renderer(QObject* parent = nullptr);
|
||||
|
||||
virtual ~Renderer() override;
|
||||
|
||||
virtual bool Init() = 0;
|
||||
|
||||
class Texture
|
||||
@@ -48,7 +46,8 @@ public:
|
||||
Texture(Renderer* renderer, const QVariant& native, const VideoParams& param) :
|
||||
renderer_(renderer),
|
||||
params_(param),
|
||||
id_(native)
|
||||
id_(native),
|
||||
meaningful_alpha_(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -67,7 +66,7 @@ public:
|
||||
return params_;
|
||||
}
|
||||
|
||||
void Upload(void* data, int linesize = 0)
|
||||
void Upload(void* data, int linesize)
|
||||
{
|
||||
renderer_->UploadToTexture(this, data, linesize);
|
||||
}
|
||||
@@ -97,6 +96,16 @@ public:
|
||||
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_;
|
||||
|
||||
@@ -104,39 +113,53 @@ public:
|
||||
|
||||
QVariant id_;
|
||||
|
||||
bool meaningful_alpha_;
|
||||
|
||||
};
|
||||
|
||||
using TexturePtr = std::shared_ptr<Texture>;
|
||||
|
||||
TexturePtr CreateTexture(const VideoParams& param, void* data = nullptr, int linesize = 0);
|
||||
|
||||
struct ShaderValue {
|
||||
QVariant data;
|
||||
NodeParam::DataType type;
|
||||
};
|
||||
|
||||
using ShaderUniformMap = QHash<QString, ShaderValue>;
|
||||
|
||||
public slots:
|
||||
virtual void PostInit() = 0;
|
||||
|
||||
virtual void Destroy() = 0;
|
||||
|
||||
virtual QVariant CreateNativeTexture(const VideoParams& param, void* data = nullptr, int linesize = 0) = 0;
|
||||
virtual void 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;
|
||||
|
||||
virtual QVariant CreateNativeShader(const ShaderCode& code) = 0;
|
||||
virtual QVariant CreateNativeShader(OLIVE_NAMESPACE::ShaderCode code) = 0;
|
||||
|
||||
virtual void DestroyNativeShader(QVariant shader) = 0;
|
||||
|
||||
virtual void UploadToTexture(Texture* texture, void* data, int linesize) = 0;
|
||||
virtual void UploadToTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) = 0;
|
||||
|
||||
virtual void DownloadFromTexture(Texture* texture, void* data, int linesize) = 0;
|
||||
virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) = 0;
|
||||
|
||||
virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node,
|
||||
const OLIVE_NAMESPACE::TimeRange &range,
|
||||
const OLIVE_NAMESPACE::ShaderJob &job,
|
||||
const OLIVE_NAMESPACE::VideoParams ¶ms) = 0;
|
||||
OLIVE_NAMESPACE::ShaderJob job,
|
||||
OLIVE_NAMESPACE::VideoParams params) = 0;
|
||||
|
||||
virtual TexturePtr TransformColor(Texture* texture, OLIVE_NAMESPACE::ColorProcessorPtr processor) = 0;
|
||||
virtual void SetViewport(int width, int height) = 0;
|
||||
|
||||
virtual void Render() = 0;
|
||||
virtual void BlitColorManaged(OLIVE_NAMESPACE::ColorProcessorPtr color_processor, OLIVE_NAMESPACE::Renderer::Texture* source, OLIVE_NAMESPACE::Renderer::Texture *destination = nullptr) = 0;
|
||||
|
||||
virtual void RenderToTexture(Texture* destination) = 0;
|
||||
virtual void Blit(OLIVE_NAMESPACE::Renderer::Texture* source, QVariant shader, OLIVE_NAMESPACE::Renderer::ShaderUniformMap parameters, OLIVE_NAMESPACE::Renderer::Texture* destination = nullptr) = 0;
|
||||
|
||||
private:
|
||||
|
||||
@@ -145,4 +168,6 @@ private:
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::Renderer::TexturePtr);
|
||||
|
||||
#endif // RENDERCONTEXT_H
|
||||
|
||||
@@ -22,12 +22,11 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
/*RendererThreadWrapper::RendererThreadWrapper(Renderer *inner, QObject *parent) :
|
||||
RendererThreadWrapper::RendererThreadWrapper(Renderer *inner, QObject *parent) :
|
||||
Renderer(parent),
|
||||
inner_(inner),
|
||||
thread_(nullptr)
|
||||
{
|
||||
inner_->setParent(this);
|
||||
}
|
||||
|
||||
bool RendererThreadWrapper::Init()
|
||||
@@ -38,11 +37,11 @@ bool RendererThreadWrapper::Init()
|
||||
}
|
||||
|
||||
// Create thread
|
||||
QThread* thread = new QThread(this);
|
||||
thread->start(QThread::IdlePriority);
|
||||
thread_ = new QThread(this);
|
||||
thread_->start(QThread::IdlePriority);
|
||||
|
||||
// Move context to thread
|
||||
inner_->moveToThread(thread);
|
||||
inner_->moveToThread(thread_);
|
||||
|
||||
// Queue post-init in new thread
|
||||
QMetaObject::invokeMethod(inner_, "PostInit", Qt::BlockingQueuedConnection);
|
||||
@@ -50,10 +49,16 @@ bool RendererThreadWrapper::Init()
|
||||
return true;
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::PostInit()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::Destroy()
|
||||
{
|
||||
if (thread_) {
|
||||
QMetaObject::invokeMethod(inner_, "Destroy", Qt::BlockingQueuedConnection);
|
||||
inner_ = nullptr;
|
||||
|
||||
thread_->quit();
|
||||
thread_->wait();
|
||||
@@ -62,76 +67,113 @@ void RendererThreadWrapper::Destroy()
|
||||
}
|
||||
}
|
||||
|
||||
QVariant RendererThreadWrapper::CreateTexture(const VideoParams ¶m, void *data, int linesize)
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
QMetaObject::invokeMethod(inner_, "CreateTexture", Qt::BlockingQueuedConnection,
|
||||
QMetaObject::invokeMethod(inner_, "CreateNativeTexture", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVariant, v),
|
||||
OLIVE_NS_CONST_ARG(VideoParams&, param),
|
||||
OLIVE_NS_ARG(VideoParams, param),
|
||||
Q_ARG(void*, data),
|
||||
Q_ARG(int, linesize));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::DestroyTexture(QVariant texture)
|
||||
void RendererThreadWrapper::DestroyNativeTexture(QVariant texture)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "DestroyTexture", Qt::BlockingQueuedConnection,
|
||||
QMetaObject::invokeMethod(inner_, "DestroyNativeTexture", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QVariant, texture));
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::UploadToTexture(QVariant texture, void *data, int linesize)
|
||||
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,
|
||||
Q_ARG(QVariant, texture),
|
||||
OLIVE_NS_ARG(Renderer::Texture*, texture),
|
||||
Q_ARG(void*, data),
|
||||
Q_ARG(int, linesize));
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::DownloadFromTexture(QVariant texture, void *data, int linesize)
|
||||
void RendererThreadWrapper::DownloadFromTexture(Renderer::Texture *texture, void *data, int linesize)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "DownloadFromTexture", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QVariant, texture),
|
||||
OLIVE_NS_ARG(Renderer::Texture*, texture),
|
||||
Q_ARG(void*, data),
|
||||
Q_ARG(int, linesize));
|
||||
}
|
||||
|
||||
QVariant RendererThreadWrapper::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job, const VideoParams ¶ms)
|
||||
Renderer::TexturePtr RendererThreadWrapper::ProcessShader(const Node *node, ShaderJob job, VideoParams params)
|
||||
{
|
||||
QVariant v;
|
||||
Renderer::TexturePtr tex;
|
||||
|
||||
QMetaObject::invokeMethod(inner_, "ProcessShader", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVariant, v),
|
||||
QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection,
|
||||
OLIVE_NS_RETURN_ARG(Renderer::TexturePtr, tex),
|
||||
OLIVE_NS_CONST_ARG(Node*, node),
|
||||
OLIVE_NS_CONST_ARG(TimeRange&, range),
|
||||
OLIVE_NS_CONST_ARG(ShaderJob&, job),
|
||||
OLIVE_NS_CONST_ARG(VideoParams&, params));
|
||||
OLIVE_NS_ARG(ShaderJob, job),
|
||||
OLIVE_NS_ARG(VideoParams, params));
|
||||
|
||||
return v;
|
||||
return tex;
|
||||
}
|
||||
|
||||
QVariant RendererThreadWrapper::TransformColor(QVariant texture, ColorProcessorPtr processor)
|
||||
void RendererThreadWrapper::SetViewport(int width, int height)
|
||||
{
|
||||
QVariant v;
|
||||
|
||||
QMetaObject::invokeMethod(inner_, "ProcessShader", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVariant, v),
|
||||
Q_ARG(QVariant, texture),
|
||||
OLIVE_NS_ARG(ColorProcessorPtr, processor));
|
||||
|
||||
return v;
|
||||
QMetaObject::invokeMethod(inner_, "SetViewport", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(int, width),
|
||||
Q_ARG(int, height));
|
||||
}
|
||||
|
||||
VideoParams RendererThreadWrapper::GetParamsFromTexture(QVariant texture)
|
||||
void RendererThreadWrapper::BlitColorManaged(ColorProcessorPtr color_processor, Renderer::Texture *source, Renderer::Texture *destination)
|
||||
{
|
||||
VideoParams p;
|
||||
QMetaObject::invokeMethod(inner_, "BlitColorManaged", Qt::BlockingQueuedConnection,
|
||||
OLIVE_NS_ARG(ColorProcessorPtr, color_processor),
|
||||
OLIVE_NS_ARG(Renderer::Texture*, source),
|
||||
OLIVE_NS_ARG(Renderer::Texture*, destination));
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(inner_, "GetParamsFromTexture", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(VideoParams, p),
|
||||
Q_ARG(QVariant, texture));
|
||||
|
||||
return p;
|
||||
}*/
|
||||
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_NAMESPACE_EXIT
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
/*class RendererThreadWrapper : public Renderer
|
||||
class RendererThreadWrapper : public Renderer
|
||||
{
|
||||
public:
|
||||
RendererThreadWrapper(Renderer* inner, QObject* parent = nullptr);
|
||||
@@ -35,39 +35,50 @@ public:
|
||||
virtual ~RendererThreadWrapper() override
|
||||
{
|
||||
Destroy();
|
||||
delete inner_;
|
||||
}
|
||||
|
||||
virtual bool Init() override;
|
||||
|
||||
public slots:
|
||||
virtual void PostInit() override{}
|
||||
virtual void PostInit() override;
|
||||
|
||||
virtual void Destroy() override;
|
||||
|
||||
virtual QVariant CreateTexture(const VideoParams& param, void* data, int linesize) override;
|
||||
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
|
||||
|
||||
virtual void DestroyTexture(QVariant texture) override;
|
||||
virtual void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture) override;
|
||||
|
||||
virtual void UploadToTexture(QVariant texture, void* data, int linesize) override;
|
||||
virtual void DetachTextureAsDestination() override;
|
||||
|
||||
virtual void DownloadFromTexture(QVariant texture, void* data, int linesize) override;
|
||||
virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) override;
|
||||
|
||||
virtual QVariant ProcessShader(const OLIVE_NAMESPACE::Node* node,
|
||||
const OLIVE_NAMESPACE::TimeRange &range,
|
||||
const OLIVE_NAMESPACE::ShaderJob &job,
|
||||
const OLIVE_NAMESPACE::VideoParams ¶ms) override;
|
||||
virtual void DestroyNativeTexture(QVariant texture) override;
|
||||
|
||||
virtual QVariant TransformColor(QVariant texture,
|
||||
OLIVE_NAMESPACE::ColorProcessorPtr processor) override;
|
||||
virtual QVariant CreateNativeShader(OLIVE_NAMESPACE::ShaderCode code) override;
|
||||
|
||||
//virtual VideoParams GetParamsFromTexture(QVariant texture) 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;
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
Renderer* inner_;
|
||||
|
||||
QThread* thread_;
|
||||
|
||||
};*/
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
|
||||
@@ -196,11 +196,11 @@ float Color::lightness() const
|
||||
|
||||
void Color::toData(char *data, const PixelFormat::Format &format) const
|
||||
{
|
||||
OIIO::convert_types(PixelFormat::GetOIIOTypeDesc(PixelFormat::PIX_FMT_RGB32F),
|
||||
OIIO::convert_types(OIIO::TypeDesc::FLOAT,
|
||||
data_,
|
||||
PixelFormat::GetOIIOTypeDesc(format),
|
||||
data,
|
||||
PixelFormat::FormatHasAlphaChannel(format) ? kRGBAChannels : kRGBChannels);
|
||||
kRGBAChannels);
|
||||
}
|
||||
|
||||
Color Color::fromData(const char *data, const PixelFormat::Format &format)
|
||||
@@ -209,13 +209,9 @@ Color Color::fromData(const char *data, const PixelFormat::Format &format)
|
||||
|
||||
OIIO::convert_types(PixelFormat::GetOIIOTypeDesc(format),
|
||||
data,
|
||||
PixelFormat::GetOIIOTypeDesc(PixelFormat::PIX_FMT_RGB32F),
|
||||
OIIO::TypeDesc::FLOAT,
|
||||
c.data_,
|
||||
PixelFormat::FormatHasAlphaChannel(format) ? kRGBAChannels : kRGBChannels);
|
||||
|
||||
if (!PixelFormat::FormatHasAlphaChannel(format)) {
|
||||
c.set_alpha(1.0f);
|
||||
}
|
||||
kRGBAChannels);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -332,11 +332,6 @@ void ColorManager::SetOCIOMethodForMode(RenderMode::Mode mode, ColorManager::OCI
|
||||
|
||||
void ColorManager::AssociateAlphaPixFmtFilter(ColorManager::AlphaAction action, FramePtr f)
|
||||
{
|
||||
if (!PixelFormat::FormatHasAlphaChannel(f->format())) {
|
||||
// This frame has no alpha channel, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
int pixel_count = f->width() * f->height() * kRGBAChannels;
|
||||
|
||||
switch (static_cast<PixelFormat::Format>(f->format())) {
|
||||
@@ -344,19 +339,15 @@ void ColorManager::AssociateAlphaPixFmtFilter(ColorManager::AlphaAction action,
|
||||
case PixelFormat::PIX_FMT_COUNT:
|
||||
qWarning() << "Alpha association functions received an invalid pixel format";
|
||||
break;
|
||||
case PixelFormat::PIX_FMT_RGB8:
|
||||
case PixelFormat::PIX_FMT_RGBA8:
|
||||
case PixelFormat::PIX_FMT_RGB16U:
|
||||
case PixelFormat::PIX_FMT_RGBA16U:
|
||||
qWarning() << "Alpha association functions only works on float-based pixel formats at this time";
|
||||
break;
|
||||
case PixelFormat::PIX_FMT_RGB16F:
|
||||
case PixelFormat::PIX_FMT_RGBA16F:
|
||||
{
|
||||
AssociateAlphaInternal<qfloat16>(action, reinterpret_cast<qfloat16*>(f->data()), pixel_count);
|
||||
break;
|
||||
}
|
||||
case PixelFormat::PIX_FMT_RGB32F:
|
||||
case PixelFormat::PIX_FMT_RGBA32F:
|
||||
{
|
||||
AssociateAlphaInternal<float>(action, reinterpret_cast<float*>(f->data()), pixel_count);
|
||||
|
||||
@@ -61,7 +61,7 @@ void ColorProcessor::ConvertFrame(Frame *f)
|
||||
OCIO::PackedImageDesc img(reinterpret_cast<float*>(f->data()),
|
||||
f->width(),
|
||||
f->height(),
|
||||
PixelFormat::ChannelCount(f->format()),
|
||||
kRGBAChannels,
|
||||
OCIO::AutoStride,
|
||||
OCIO::AutoStride,
|
||||
f->linesize_bytes());
|
||||
|
||||
@@ -26,7 +26,18 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
using DecoderCache = QHash<Stream*, DecoderPtr>;
|
||||
class DecoderCache : public QHash<Stream*, DecoderPtr>
|
||||
{
|
||||
public:
|
||||
QMutex *mutex()
|
||||
{
|
||||
return &mutex_;
|
||||
}
|
||||
|
||||
private:
|
||||
QMutex mutex_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
|
||||
@@ -245,17 +245,9 @@ FramePtr FrameHashCache::LoadCacheFrame(const QString &fn)
|
||||
|
||||
PixelFormat::Format image_format;
|
||||
if (pix_type == Imf::HALF) {
|
||||
if (has_alpha) {
|
||||
image_format = PixelFormat::PIX_FMT_RGBA16F;
|
||||
} else {
|
||||
image_format = PixelFormat::PIX_FMT_RGB16F;
|
||||
}
|
||||
} else {
|
||||
if (has_alpha) {
|
||||
image_format = PixelFormat::PIX_FMT_RGBA32F;
|
||||
} else {
|
||||
image_format = PixelFormat::PIX_FMT_RGB32F;
|
||||
}
|
||||
}
|
||||
|
||||
frame = Frame::Create();
|
||||
@@ -268,7 +260,7 @@ FramePtr FrameHashCache::LoadCacheFrame(const QString &fn)
|
||||
|
||||
int bpc = PixelFormat::BytesPerChannel(image_format);
|
||||
|
||||
size_t xs = PixelFormat::ChannelCount(image_format) * bpc;
|
||||
size_t xs = kRGBAChannels * bpc;
|
||||
size_t ys = frame->linesize_bytes();
|
||||
|
||||
Imf::FrameBuffer framebuffer;
|
||||
@@ -411,8 +403,7 @@ bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const V
|
||||
// Floating point types are stored in EXR
|
||||
Imf::PixelType pix_type;
|
||||
|
||||
if (vparam.format() == PixelFormat::PIX_FMT_RGB16F
|
||||
|| vparam.format() == PixelFormat::PIX_FMT_RGBA16F) {
|
||||
if (vparam.format() == PixelFormat::PIX_FMT_RGBA16F) {
|
||||
pix_type = Imf::HALF;
|
||||
} else {
|
||||
pix_type = Imf::FLOAT;
|
||||
@@ -423,9 +414,7 @@ bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const V
|
||||
header.channels().insert("R", Imf::Channel(pix_type));
|
||||
header.channels().insert("G", Imf::Channel(pix_type));
|
||||
header.channels().insert("B", Imf::Channel(pix_type));
|
||||
if (PixelFormat::FormatHasAlphaChannel(vparam.format())) {
|
||||
header.channels().insert("A", Imf::Channel(pix_type));
|
||||
}
|
||||
|
||||
header.compression() = Imf::DWAA_COMPRESSION;
|
||||
header.insert("dwaCompressionLevel", Imf::FloatAttribute(200.0f));
|
||||
@@ -435,16 +424,14 @@ bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const V
|
||||
|
||||
int bpc = PixelFormat::BytesPerChannel(vparam.format());
|
||||
|
||||
size_t xs = PixelFormat::ChannelCount(vparam.format()) * bpc;
|
||||
size_t xs = kRGBAChannels * bpc;
|
||||
size_t ys = linesize_bytes;
|
||||
|
||||
Imf::FrameBuffer framebuffer;
|
||||
framebuffer.insert("R", Imf::Slice(pix_type, data, xs, ys));
|
||||
framebuffer.insert("G", Imf::Slice(pix_type, data + bpc, xs, ys));
|
||||
framebuffer.insert("B", Imf::Slice(pix_type, data + 2*bpc, xs, ys));
|
||||
if (PixelFormat::FormatHasAlphaChannel(vparam.format())) {
|
||||
framebuffer.insert("A", Imf::Slice(pix_type, data + 3*bpc, xs, ys));
|
||||
}
|
||||
out.setFrameBuffer(framebuffer);
|
||||
|
||||
out.writePixels(vparam.effective_height());
|
||||
|
||||
+11
-102
@@ -25,44 +25,20 @@
|
||||
#include <QDebug>
|
||||
#include <QFloat16>
|
||||
|
||||
#include "codec/oiio/oiiodecoder.h"
|
||||
#include "codec/oiio/oiiocommon.h"
|
||||
#include "common/define.h"
|
||||
#include "core.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
bool PixelFormat::FormatHasAlphaChannel(const PixelFormat::Format &format)
|
||||
{
|
||||
switch (format) {
|
||||
case PixelFormat::PIX_FMT_RGBA8:
|
||||
case PixelFormat::PIX_FMT_RGBA16U:
|
||||
case PixelFormat::PIX_FMT_RGBA16F:
|
||||
case PixelFormat::PIX_FMT_RGBA32F:
|
||||
return true;
|
||||
case PixelFormat::PIX_FMT_RGB8:
|
||||
case PixelFormat::PIX_FMT_RGB16U:
|
||||
case PixelFormat::PIX_FMT_RGB16F:
|
||||
case PixelFormat::PIX_FMT_RGB32F:
|
||||
case PixelFormat::PIX_FMT_INVALID:
|
||||
case PixelFormat::PIX_FMT_COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PixelFormat::FormatIsFloat(const PixelFormat::Format &format)
|
||||
{
|
||||
switch (format) {
|
||||
case PixelFormat::PIX_FMT_RGB16F:
|
||||
case PixelFormat::PIX_FMT_RGBA16F:
|
||||
case PixelFormat::PIX_FMT_RGB32F:
|
||||
case PixelFormat::PIX_FMT_RGBA32F:
|
||||
return true;
|
||||
|
||||
case PixelFormat::PIX_FMT_RGB8:
|
||||
case PixelFormat::PIX_FMT_RGBA8:
|
||||
case PixelFormat::PIX_FMT_RGB16U:
|
||||
case PixelFormat::PIX_FMT_RGBA16U:
|
||||
case PixelFormat::PIX_FMT_INVALID:
|
||||
case PixelFormat::PIX_FMT_COUNT:
|
||||
@@ -75,16 +51,12 @@ bool PixelFormat::FormatIsFloat(const PixelFormat::Format &format)
|
||||
OIIO::TypeDesc::BASETYPE PixelFormat::GetOIIOTypeDesc(const PixelFormat::Format &format)
|
||||
{
|
||||
switch (format) {
|
||||
case PixelFormat::PIX_FMT_RGB8:
|
||||
case PixelFormat::PIX_FMT_RGBA8:
|
||||
return OIIO::TypeDesc::UINT8;
|
||||
case PixelFormat::PIX_FMT_RGB16U:
|
||||
case PixelFormat::PIX_FMT_RGBA16U:
|
||||
return OIIO::TypeDesc::UINT16;
|
||||
case PixelFormat::PIX_FMT_RGB16F:
|
||||
case PixelFormat::PIX_FMT_RGBA16F:
|
||||
return OIIO::TypeDesc::HALF;
|
||||
case PixelFormat::PIX_FMT_RGB32F:
|
||||
case PixelFormat::PIX_FMT_RGBA32F:
|
||||
return OIIO::TypeDesc::FLOAT;
|
||||
case PixelFormat::PIX_FMT_INVALID:
|
||||
@@ -98,16 +70,12 @@ OIIO::TypeDesc::BASETYPE PixelFormat::GetOIIOTypeDesc(const PixelFormat::Format
|
||||
QString PixelFormat::GetName(const PixelFormat::Format &format)
|
||||
{
|
||||
switch (format) {
|
||||
case PixelFormat::PIX_FMT_RGB8:
|
||||
case PixelFormat::PIX_FMT_RGBA8:
|
||||
return tr("8-bit");
|
||||
case PixelFormat::PIX_FMT_RGB16U:
|
||||
case PixelFormat::PIX_FMT_RGBA16U:
|
||||
return tr("16-bit Integer");
|
||||
case PixelFormat::PIX_FMT_RGB16F:
|
||||
case PixelFormat::PIX_FMT_RGBA16F:
|
||||
return tr("Half-Float (16-bit)");
|
||||
case PixelFormat::PIX_FMT_RGB32F:
|
||||
case PixelFormat::PIX_FMT_RGBA32F:
|
||||
return tr("Full-Float (32-bit)");
|
||||
case PixelFormat::PIX_FMT_INVALID:
|
||||
@@ -149,67 +117,21 @@ void PixelFormat::SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat:
|
||||
}
|
||||
}
|
||||
|
||||
PixelFormat::Format PixelFormat::OIIOFormatToOliveFormat(OIIO::TypeDesc desc, bool has_alpha)
|
||||
PixelFormat::Format PixelFormat::OIIOFormatToOliveFormat(OIIO::TypeDesc desc)
|
||||
{
|
||||
if (desc == OIIO::TypeDesc::UINT8) {
|
||||
return has_alpha ? PixelFormat::PIX_FMT_RGBA8 : PixelFormat::PIX_FMT_RGB8;
|
||||
return PixelFormat::PIX_FMT_RGBA8;
|
||||
} else if (desc == OIIO::TypeDesc::UINT16) {
|
||||
return has_alpha ? PixelFormat::PIX_FMT_RGBA16U : PixelFormat::PIX_FMT_RGB16U;
|
||||
return PixelFormat::PIX_FMT_RGBA16U;
|
||||
} else if (desc == OIIO::TypeDesc::HALF) {
|
||||
return has_alpha ? PixelFormat::PIX_FMT_RGBA16F : PixelFormat::PIX_FMT_RGB16F;
|
||||
return PixelFormat::PIX_FMT_RGBA16F;
|
||||
} else if (desc == OIIO::TypeDesc::FLOAT) {
|
||||
return has_alpha ? PixelFormat::PIX_FMT_RGBA32F : PixelFormat::PIX_FMT_RGB32F;
|
||||
return PixelFormat::PIX_FMT_RGBA32F;
|
||||
}
|
||||
|
||||
return PixelFormat::PIX_FMT_INVALID;
|
||||
}
|
||||
|
||||
PixelFormat::Format PixelFormat::GetFormatWithAlphaChannel(PixelFormat::Format f)
|
||||
{
|
||||
switch (f) {
|
||||
case PIX_FMT_INVALID:
|
||||
case PIX_FMT_COUNT:
|
||||
break;
|
||||
case PIX_FMT_RGB8:
|
||||
case PIX_FMT_RGBA8:
|
||||
return PIX_FMT_RGBA8;
|
||||
case PIX_FMT_RGB16U:
|
||||
case PIX_FMT_RGBA16U:
|
||||
return PIX_FMT_RGBA16U;
|
||||
case PIX_FMT_RGB16F:
|
||||
case PIX_FMT_RGBA16F:
|
||||
return PIX_FMT_RGBA16F;
|
||||
case PIX_FMT_RGB32F:
|
||||
case PIX_FMT_RGBA32F:
|
||||
return PIX_FMT_RGBA32F;
|
||||
}
|
||||
|
||||
return PIX_FMT_INVALID;
|
||||
}
|
||||
|
||||
PixelFormat::Format PixelFormat::GetFormatWithoutAlphaChannel(PixelFormat::Format f)
|
||||
{
|
||||
switch (f) {
|
||||
case PIX_FMT_INVALID:
|
||||
case PIX_FMT_COUNT:
|
||||
break;
|
||||
case PIX_FMT_RGB8:
|
||||
case PIX_FMT_RGBA8:
|
||||
return PIX_FMT_RGB8;
|
||||
case PIX_FMT_RGB16U:
|
||||
case PIX_FMT_RGBA16U:
|
||||
return PIX_FMT_RGB16U;
|
||||
case PIX_FMT_RGB16F:
|
||||
case PIX_FMT_RGBA16F:
|
||||
return PIX_FMT_RGB16F;
|
||||
case PIX_FMT_RGB32F:
|
||||
case PIX_FMT_RGBA32F:
|
||||
return PIX_FMT_RGB32F;
|
||||
}
|
||||
|
||||
return PIX_FMT_INVALID;
|
||||
}
|
||||
|
||||
int PixelFormat::GetBufferSize(const PixelFormat::Format &format, const int &width, const int &height)
|
||||
{
|
||||
return BytesPerPixel(format) * width * height;
|
||||
@@ -217,21 +139,17 @@ int PixelFormat::GetBufferSize(const PixelFormat::Format &format, const int &wid
|
||||
|
||||
int PixelFormat::BytesPerPixel(const PixelFormat::Format &format)
|
||||
{
|
||||
return BytesPerChannel(format) * ChannelCount(format);
|
||||
return BytesPerChannel(format) * kRGBAChannels;
|
||||
}
|
||||
|
||||
int PixelFormat::BytesPerChannel(const PixelFormat::Format &format)
|
||||
{
|
||||
switch (format) {
|
||||
case PixelFormat::PIX_FMT_RGB8:
|
||||
case PixelFormat::PIX_FMT_RGBA8:
|
||||
return 1;
|
||||
case PixelFormat::PIX_FMT_RGB16U:
|
||||
case PixelFormat::PIX_FMT_RGB16F:
|
||||
case PixelFormat::PIX_FMT_RGBA16U:
|
||||
case PixelFormat::PIX_FMT_RGBA16F:
|
||||
return 2;
|
||||
case PixelFormat::PIX_FMT_RGB32F:
|
||||
case PixelFormat::PIX_FMT_RGBA32F:
|
||||
return 4;
|
||||
case PixelFormat::PIX_FMT_INVALID:
|
||||
@@ -245,15 +163,6 @@ int PixelFormat::BytesPerChannel(const PixelFormat::Format &format)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PixelFormat::ChannelCount(const PixelFormat::Format &format)
|
||||
{
|
||||
if (PixelFormat::FormatHasAlphaChannel(format)) {
|
||||
return kRGBAChannels;
|
||||
} else {
|
||||
return kRGBChannels;
|
||||
}
|
||||
}
|
||||
|
||||
FramePtr PixelFormat::ConvertPixelFormat(FramePtr frame, const PixelFormat::Format &dest_format)
|
||||
{
|
||||
if (frame->format() == dest_format) {
|
||||
@@ -271,23 +180,23 @@ FramePtr PixelFormat::ConvertPixelFormat(FramePtr frame, const PixelFormat::Form
|
||||
// Do the conversion through OIIO - create a buffer for the source image
|
||||
OIIO::ImageBuf src(OIIO::ImageSpec(frame->width(),
|
||||
frame->height(),
|
||||
ChannelCount(frame->format()),
|
||||
kRGBAChannels,
|
||||
GetOIIOTypeDesc(frame->format())));
|
||||
|
||||
// Set the pixels (this is necessary as opposed to an OIIO buffer wrapper since Frame has
|
||||
// linesizes)
|
||||
OIIODecoder::FrameToBuffer(frame, &src);
|
||||
OIIOCommon::FrameToBuffer(frame, &src);
|
||||
|
||||
// Create a destination OIIO buffer with our destination format
|
||||
OIIO::ImageBuf dst(OIIO::ImageSpec(converted->width(),
|
||||
converted->height(),
|
||||
ChannelCount(converted->format()),
|
||||
kRGBAChannels,
|
||||
GetOIIOTypeDesc(converted->format())));
|
||||
|
||||
if (dst.copy_pixels(src)) {
|
||||
|
||||
// Convert our buffer back to a frame
|
||||
OIIODecoder::BufferToFrame(&dst, converted);
|
||||
OIIOCommon::BufferToFrame(&dst, converted);
|
||||
|
||||
return converted;
|
||||
} else {
|
||||
|
||||
@@ -48,11 +48,6 @@ public:
|
||||
PIX_FMT_RGBA16F,
|
||||
PIX_FMT_RGBA32F,
|
||||
|
||||
PIX_FMT_RGB8,
|
||||
PIX_FMT_RGB16U,
|
||||
PIX_FMT_RGB16F,
|
||||
PIX_FMT_RGB32F,
|
||||
|
||||
PIX_FMT_COUNT
|
||||
};
|
||||
|
||||
@@ -66,10 +61,7 @@ public:
|
||||
Format GetConfiguredFormatForMode(RenderMode::Mode mode);
|
||||
void SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format);
|
||||
|
||||
static Format OIIOFormatToOliveFormat(OIIO::TypeDesc desc, bool has_alpha);
|
||||
|
||||
static Format GetFormatWithAlphaChannel(Format f);
|
||||
static Format GetFormatWithoutAlphaChannel(Format f);
|
||||
static Format OIIOFormatToOliveFormat(OIIO::TypeDesc desc);
|
||||
|
||||
/**
|
||||
* @brief Returns the minimum buffer size (in bytes) necessary for a given format, width, and height.
|
||||
@@ -102,11 +94,6 @@ public:
|
||||
*/
|
||||
static int BytesPerChannel(const Format& format);
|
||||
|
||||
/**
|
||||
* @brief Return the number of channels in this format
|
||||
*/
|
||||
static int ChannelCount(const Format& format);
|
||||
|
||||
/**
|
||||
* @brief Convert a frame to a pixel format
|
||||
*
|
||||
@@ -114,11 +101,6 @@ public:
|
||||
*/
|
||||
static FramePtr ConvertPixelFormat(FramePtr frame, const Format &dest_format);
|
||||
|
||||
/**
|
||||
* @brief Simple convenience function returning whether a pixel format has an alpha channel or not
|
||||
*/
|
||||
static bool FormatHasAlphaChannel(const Format& format);
|
||||
|
||||
/**
|
||||
* @brief Simple convenience function returning whether a pixel format is float-based or integer-based
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <QApplication>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
#include "project/item/sequence/sequence.h"
|
||||
#include "project/project.h"
|
||||
#include "render/rendermanager.h"
|
||||
#include "render/renderprocessor.h"
|
||||
|
||||
@@ -13,6 +15,7 @@ PreviewAutoCacher::PreviewAutoCacher() :
|
||||
paused_(false),
|
||||
has_changed_(false),
|
||||
use_custom_range_(false),
|
||||
single_frame_render_(nullptr),
|
||||
last_update_time_(0),
|
||||
ignore_next_mouse_button_(false),
|
||||
video_params_changed_(false),
|
||||
@@ -24,13 +27,20 @@ PreviewAutoCacher::PreviewAutoCacher() :
|
||||
|
||||
RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t)
|
||||
{
|
||||
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
|
||||
if (single_frame_render_) {
|
||||
single_frame_render_->Cancel();
|
||||
}
|
||||
|
||||
ticket->setProperty("time", QVariant::fromValue(t));
|
||||
single_frame_render_ = std::make_shared<RenderTicket>();
|
||||
|
||||
single_frame_render_->setProperty("time", QVariant::fromValue(t));
|
||||
|
||||
// Copy because TryRender() might set this to null and we still want to return a handle to this
|
||||
RenderTicketPtr copy = single_frame_render_;
|
||||
|
||||
TryRender();
|
||||
|
||||
return ticket;
|
||||
return copy;
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::SetPaused(bool paused)
|
||||
@@ -299,6 +309,14 @@ void PreviewAutoCacher::AudioParamsChanged()
|
||||
TryRender();
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::SingleFrameFinished()
|
||||
{
|
||||
RenderTicketWatcher* watcher = static_cast<RenderTicketWatcher*>(sender());
|
||||
RenderTicketPtr passthrough = watcher->property("passthrough").value<RenderTicketPtr>();
|
||||
passthrough->Finish(watcher->GetTicket()->Get(), watcher->GetTicket()->WasCancelled());
|
||||
delete watcher;
|
||||
}
|
||||
|
||||
//#define PRINT_UPDATE_QUEUE_INFO
|
||||
void PreviewAutoCacher::ProcessUpdateQueue()
|
||||
{
|
||||
@@ -554,23 +572,21 @@ void PreviewAutoCacher::TryRender()
|
||||
invalidated_audio_.clear();
|
||||
}
|
||||
|
||||
if (!single_frame_renders_.isEmpty()) {
|
||||
foreach (RenderTicketPtr ticket, single_frame_renders_) {
|
||||
if (single_frame_render_) {
|
||||
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
||||
|
||||
watcher->setProperty("passthrough", QVariant::fromValue(ticket));
|
||||
watcher->setProperty("passthrough", QVariant::fromValue(single_frame_render_));
|
||||
|
||||
connect(watcher, &RenderTicketWatcher::Finished, watcher, [watcher]{
|
||||
RenderTicketPtr passthrough = watcher->property("passthrough").value<RenderTicketPtr>();
|
||||
passthrough->Finish(watcher->GetTicket()->Get(), watcher->GetTicket()->WasCancelled());
|
||||
watcher->deleteLater();
|
||||
});
|
||||
connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::SingleFrameFinished);
|
||||
|
||||
single_frame_render_->Start();
|
||||
|
||||
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_,
|
||||
ticket->property("time").value<rational>(),
|
||||
static_cast<Sequence*>(viewer_node_->parent())->project()->color_manager(),
|
||||
single_frame_render_->property("time").value<rational>(),
|
||||
RenderMode::kOffline, true));
|
||||
}
|
||||
single_frame_renders_.clear();
|
||||
|
||||
single_frame_render_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,7 +623,9 @@ void PreviewAutoCacher::RequeueFrames()
|
||||
watcher->setProperty("hash", hash);
|
||||
connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::VideoRendered);
|
||||
video_tasks_.insert(watcher, hash);
|
||||
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_, t, RenderMode::kOffline, false));
|
||||
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_,
|
||||
static_cast<Sequence*>(viewer_node_->parent())->project()->color_manager(),
|
||||
t, RenderMode::kOffline, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ private:
|
||||
TimeRangeList invalidated_video_;
|
||||
TimeRangeList invalidated_audio_;
|
||||
|
||||
QVector<RenderTicketPtr> single_frame_renders_;
|
||||
RenderTicketPtr single_frame_render_;
|
||||
|
||||
QList<QFutureWatcher<void>*> hash_tasks_;
|
||||
QMap<RenderTicketWatcher*, TimeRange> audio_tasks_;
|
||||
@@ -192,6 +192,8 @@ private slots:
|
||||
|
||||
void AudioParamsChanged();
|
||||
|
||||
void SingleFrameFinished();
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -39,10 +39,36 @@ OLIVE_NAMESPACE_ENTER
|
||||
RenderManager* RenderManager::instance_ = nullptr;
|
||||
|
||||
RenderManager::RenderManager(QObject *parent) :
|
||||
ThreadPool(QThread::IdlePriority, 0, parent)
|
||||
ThreadPool(QThread::IdlePriority, 0, parent),
|
||||
backend_(kOpenGL)
|
||||
{
|
||||
context_ = new RendererThreadWrapper(new OpenGLRenderer(), this);
|
||||
Renderer* graphics_renderer = nullptr;
|
||||
|
||||
if (backend_ == kOpenGL) {
|
||||
graphics_renderer = new OpenGLRenderer();
|
||||
}
|
||||
|
||||
if (graphics_renderer) {
|
||||
context_ = new RendererThreadWrapper(graphics_renderer, this);
|
||||
context_->Init();
|
||||
context_->PostInit();
|
||||
|
||||
still_cache_ = new StillImageCache();
|
||||
decoder_cache_ = new DecoderCache();
|
||||
} else {
|
||||
qCritical() << "Tried to initialize unknown graphics backend";
|
||||
still_cache_ = nullptr;
|
||||
decoder_cache_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RenderManager::~RenderManager()
|
||||
{
|
||||
delete decoder_cache_;
|
||||
delete still_cache_;
|
||||
|
||||
context_->Destroy();
|
||||
delete context_;
|
||||
}
|
||||
|
||||
QByteArray RenderManager::Hash(const Node *n, const VideoParams ¶ms, const rational &time)
|
||||
@@ -50,9 +76,13 @@ QByteArray RenderManager::Hash(const Node *n, const VideoParams ¶ms, const r
|
||||
QCryptographicHash hasher(QCryptographicHash::Sha1);
|
||||
|
||||
// Embed video parameters into this hash
|
||||
hasher.addData(reinterpret_cast<const char*>(¶ms.effective_width()), sizeof(int));
|
||||
hasher.addData(reinterpret_cast<const char*>(¶ms.effective_height()), sizeof(int));
|
||||
hasher.addData(reinterpret_cast<const char*>(¶ms.format()), sizeof(PixelFormat::Format));
|
||||
int width = params.effective_width();
|
||||
int height = params.effective_height();
|
||||
PixelFormat::Format format = params.format();
|
||||
|
||||
hasher.addData(reinterpret_cast<const char*>(&width), sizeof(int));
|
||||
hasher.addData(reinterpret_cast<const char*>(&height), sizeof(int));
|
||||
hasher.addData(reinterpret_cast<const char*>(&format), sizeof(PixelFormat::Format));
|
||||
|
||||
if (n) {
|
||||
n->Hash(hasher, time);
|
||||
@@ -61,15 +91,18 @@ QByteArray RenderManager::Hash(const Node *n, const VideoParams ¶ms, const r
|
||||
return hasher.result();
|
||||
}
|
||||
|
||||
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, const rational &time, RenderMode::Mode mode, bool prioritize)
|
||||
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager *color_manager, const rational &time, RenderMode::Mode mode, bool prioritize)
|
||||
{
|
||||
return RenderFrame(viewer, time, mode,
|
||||
QSize(),
|
||||
return RenderFrame(viewer,
|
||||
color_manager,
|
||||
time,
|
||||
mode,
|
||||
QSize(0, 0),
|
||||
QMatrix4x4(),
|
||||
prioritize);
|
||||
}
|
||||
|
||||
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, const rational &time, RenderMode::Mode mode, const QSize &force_size, const QMatrix4x4 &matrix, bool prioritize)
|
||||
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, const rational &time, RenderMode::Mode mode, const QSize &force_size, const QMatrix4x4 &matrix, bool prioritize)
|
||||
{
|
||||
// Create ticket
|
||||
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
|
||||
@@ -81,6 +114,7 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, const rational
|
||||
ticket->setProperty("mode", mode);
|
||||
ticket->setProperty("type", kTypeVideo);
|
||||
ticket->setProperty("cache", viewer->video_frame_cache()->GetCacheDirectory());
|
||||
ticket->setProperty("colormanager", Node::PtrToValue(color_manager));
|
||||
|
||||
// Queue appending the ticket and running the next job on our thread to make this function thread-safe
|
||||
QMetaObject::invokeMethod(this, "AddTicket", Qt::AutoConnection,
|
||||
@@ -128,7 +162,7 @@ RenderTicketPtr RenderManager::SaveFrameToCache(FrameHashCache *cache, FramePtr
|
||||
|
||||
void RenderManager::RunTicket(RenderTicketPtr ticket) const
|
||||
{
|
||||
RenderProcessor::Process(ticket, context_);
|
||||
RenderProcessor::Process(ticket, context_, still_cache_, decoder_cache_);
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "node/output/viewer/viewer.h"
|
||||
#include "node/traverser.h"
|
||||
#include "render/backend/renderer.h"
|
||||
#include "stillimagecache.h"
|
||||
#include "threading/threadpool.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
@@ -79,8 +80,8 @@ public:
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*/
|
||||
RenderTicketPtr RenderFrame(ViewerOutput* viewer, const rational& time, RenderMode::Mode mode, bool prioritize = false);
|
||||
RenderTicketPtr RenderFrame(ViewerOutput* viewer, const rational& time, RenderMode::Mode mode, const QSize& force_size, const QMatrix4x4& matrix, bool prioritize = false);
|
||||
RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, bool prioritize = false);
|
||||
RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, const QSize& force_size, const QMatrix4x4& matrix, bool prioritize = false);
|
||||
|
||||
/**
|
||||
* @brief Asynchronously generate a chunk of audio
|
||||
@@ -104,15 +105,28 @@ public:
|
||||
kTypeVideoDownload
|
||||
};
|
||||
|
||||
Backend backend() const
|
||||
{
|
||||
return backend_;
|
||||
}
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
RenderManager(QObject* parent = nullptr);
|
||||
|
||||
virtual ~RenderManager() override;
|
||||
|
||||
static RenderManager* instance_;
|
||||
|
||||
Renderer* context_;
|
||||
|
||||
Backend backend_;
|
||||
|
||||
StillImageCache* still_cache_;
|
||||
|
||||
DecoderCache* decoder_cache_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -24,13 +24,16 @@
|
||||
#include <QVector3D>
|
||||
#include <QVector4D>
|
||||
|
||||
#include "project/project.h"
|
||||
#include "rendermanager.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx) :
|
||||
RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache) :
|
||||
ticket_(ticket),
|
||||
render_ctx_(render_ctx)
|
||||
render_ctx_(render_ctx),
|
||||
still_image_cache_(still_image_cache),
|
||||
decoder_cache_(decoder_cache)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -52,21 +55,17 @@ void RenderProcessor::Run()
|
||||
|
||||
Renderer::TexturePtr texture = table.Get(NodeParam::kTexture).value<Renderer::TexturePtr>();
|
||||
|
||||
VideoParams frame_params = viewer->video_params();
|
||||
|
||||
QSize frame_size = ticket_->property("size").value<QSize>();
|
||||
if (frame_size.isNull()) {
|
||||
frame_size = QSize(viewer->video_params().effective_width(),
|
||||
viewer->video_params().effective_height());
|
||||
if (!frame_size.isNull()) {
|
||||
frame_params.set_width(frame_size.width());
|
||||
frame_params.set_height(frame_size.height());
|
||||
}
|
||||
|
||||
FramePtr frame = Frame::Create();
|
||||
frame->set_timestamp(time);
|
||||
frame->set_video_params(VideoParams(frame_size.width(),
|
||||
frame_size.height(),
|
||||
viewer->video_params().time_base(),
|
||||
viewer->video_params().format(),
|
||||
viewer->video_params().pixel_aspect_ratio(),
|
||||
viewer->video_params().interlacing(),
|
||||
viewer->video_params().divider()));
|
||||
frame->set_video_params(frame_params);
|
||||
frame->allocate();
|
||||
|
||||
if (!texture) {
|
||||
@@ -109,13 +108,38 @@ void RenderProcessor::Run()
|
||||
// Fail
|
||||
ticket_->Cancel();
|
||||
}
|
||||
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx)
|
||||
DecoderPtr RenderProcessor::ResolveDecoderFromInput(StreamPtr stream)
|
||||
{
|
||||
RenderProcessor p(ticket, render_ctx);
|
||||
if (!stream) {
|
||||
qWarning() << "Attempted to resolve the decoder of a null stream";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QMutexLocker locker(decoder_cache_->mutex());
|
||||
|
||||
DecoderPtr decoder = decoder_cache_->value(stream.get());
|
||||
|
||||
if (!decoder) {
|
||||
// No decoder
|
||||
decoder = Decoder::CreateFromID(stream->footage()->decoder());
|
||||
|
||||
if (decoder->Open(stream)) {
|
||||
decoder_cache_->insert(stream.get(), decoder);
|
||||
} else {
|
||||
qWarning() << "Failed to open decoder for" << stream->footage()->filename()
|
||||
<< "::" << stream->index();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache *still_image_cache, DecoderCache *decoder_cache)
|
||||
{
|
||||
RenderProcessor p(ticket, render_ctx, still_image_cache, decoder_cache);
|
||||
p.Run();
|
||||
}
|
||||
|
||||
@@ -259,11 +283,24 @@ QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &
|
||||
|
||||
if (frame) {
|
||||
// Return a texture from the derived class
|
||||
Renderer::TexturePtr unmanaged_texture = render_ctx_->CreateTexture(frame->video_params(), frame->data(), frame->linesize_pixels());
|
||||
Renderer::TexturePtr unmanaged_texture = render_ctx_->CreateTexture(frame->video_params(),
|
||||
frame->data(),
|
||||
frame->linesize_pixels());
|
||||
|
||||
Renderer::TexturePtr managed_texture = render_ctx_->TransformColor(unmanaged_texture, )
|
||||
// We convert to our rendering pixel format, since that will always be float-based which
|
||||
// is necessary for correct color conversion
|
||||
VideoParams managed_params = frame->video_params();
|
||||
managed_params.set_format(video_params.format());
|
||||
value = render_ctx_->CreateTexture(managed_params);
|
||||
|
||||
value = FootageFrameToTexture(stream, frame);
|
||||
// FIXME: Accessing video_stream->colorspace()
|
||||
|
||||
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());
|
||||
|
||||
still_image_cache_->mutex()->lock();
|
||||
|
||||
@@ -290,49 +327,23 @@ QVariant RenderProcessor::ProcessAudioFootage(StreamPtr stream, const TimeRange
|
||||
if (decoder) {
|
||||
const AudioParams& audio_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->audio_params();
|
||||
|
||||
// See if we have a conformed version of this audio
|
||||
if (!decoder->HasConformedVersion(audio_params)) {
|
||||
|
||||
// If not, the audio needs to be conformed
|
||||
// For online rendering/export, it's a waste of time to render the audio until we have
|
||||
// all we need, so we try to handle the conform ourselves
|
||||
AudioStreamPtr as = std::static_pointer_cast<AudioStream>(stream);
|
||||
|
||||
// Check if any other threads are conforming this audio
|
||||
if (as->try_start_conforming(audio_params)) {
|
||||
|
||||
// If not, conform it ourselves
|
||||
decoder->ConformAudio(&IsCancelled(), audio_params);
|
||||
|
||||
} else {
|
||||
|
||||
// If another thread is conforming already, hackily try to wait until it's done.
|
||||
do {
|
||||
QThread::msleep(1000);
|
||||
} while (!as->has_conformed_version(audio_params) && !IsCancelled());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (decoder->HasConformedVersion(audio_params)) {
|
||||
SampleBufferPtr frame = decoder->RetrieveAudio(input_time.in(), input_time.length(),
|
||||
audio_params);
|
||||
SampleBufferPtr frame = decoder->RetrieveAudio(input_time, audio_params, &IsCancelled());
|
||||
|
||||
if (frame) {
|
||||
value = QVariant::fromValue(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
QVariant RenderProcessor::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job)
|
||||
{
|
||||
Q_UNUSED(range)
|
||||
|
||||
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
|
||||
|
||||
render_ctx_->ProcessShader(node, range, job, video_params);
|
||||
return QVariant::fromValue(render_ctx_->ProcessShader(node, job, video_params));
|
||||
}
|
||||
|
||||
QVariant RenderProcessor::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job)
|
||||
@@ -384,49 +395,39 @@ QVariant RenderProcessor::ProcessFrameGeneration(const Node *node, const Generat
|
||||
|
||||
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
|
||||
|
||||
PixelFormat::Format output_fmt;
|
||||
if (job.GetAlphaChannelRequired()) {
|
||||
output_fmt = PixelFormat::GetFormatWithAlphaChannel(video_params.format());
|
||||
} else {
|
||||
output_fmt = PixelFormat::GetFormatWithoutAlphaChannel(video_params.format());
|
||||
}
|
||||
|
||||
frame->set_video_params(VideoParams(video_params.width(),
|
||||
video_params.height(),
|
||||
video_params.time_base(),
|
||||
output_fmt,
|
||||
video_params.pixel_aspect_ratio(),
|
||||
video_params.interlacing(),
|
||||
video_params.divider()));
|
||||
frame->set_video_params(video_params);
|
||||
frame->allocate();
|
||||
|
||||
node->GenerateFrame(frame, job);
|
||||
|
||||
Renderer::TexturePtr texture = render_ctx_->CreateTexture(frame->video_params(), frame->data(), frame->linesize_pixels());
|
||||
Renderer::TexturePtr texture = render_ctx_->CreateTexture(frame->video_params(),
|
||||
frame->data(),
|
||||
frame->linesize_pixels());
|
||||
|
||||
texture->set_has_meaningful_alpha(job.GetAlphaChannelRequired());
|
||||
|
||||
return QVariant::fromValue(texture);
|
||||
}
|
||||
|
||||
QVariant RenderProcessor::GetCachedFrame(const Node *node, const rational &time)
|
||||
{
|
||||
if (ticket_->property("mode").value<RenderMode::Mode>() == RenderMode::kOffline
|
||||
&& !cache_path_.isEmpty()
|
||||
if (ticket_->property("mode").toInt() == RenderMode::kOffline
|
||||
&& node->id() == QStringLiteral("org.olivevideoeditor.Olive.videoinput")) {
|
||||
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
|
||||
|
||||
QByteArray hash = RenderManager::Hash(node, video_params, time);
|
||||
|
||||
FramePtr f = FrameHashCache::LoadCacheFrame(cache_path_, hash);
|
||||
FramePtr f = FrameHashCache::LoadCacheFrame(ticket_->property("cache").toString(), hash);
|
||||
|
||||
if (f) {
|
||||
// The cached frame won't load with the correct divider by default, so we enforce it here
|
||||
f->set_video_params(VideoParams(f->width() * video_params.divider(),
|
||||
f->height() * video_params.divider(),
|
||||
f->video_params().time_base(),
|
||||
f->video_params().format(),
|
||||
f->video_params().pixel_aspect_ratio(),
|
||||
f->video_params().interlacing(),
|
||||
video_params.divider()));
|
||||
VideoParams p = f->video_params();
|
||||
|
||||
p.set_width(f->width() * video_params.divider());
|
||||
p.set_height(f->height() * video_params.divider());
|
||||
p.set_divider(video_params.divider());
|
||||
|
||||
f->set_video_params(p);
|
||||
|
||||
Renderer::TexturePtr texture = render_ctx_->CreateTexture(f->video_params(), f->data(), f->linesize_pixels());
|
||||
return QVariant::fromValue(texture);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef RENDERPROCESSOR_H
|
||||
#define RENDERPROCESSOR_H
|
||||
|
||||
#include "decodercache.h"
|
||||
#include "node/traverser.h"
|
||||
#include "render/backend/renderer.h"
|
||||
#include "stillimagecache.h"
|
||||
@@ -28,11 +29,10 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class RenderProcessor : public QObject, public NodeTraverser
|
||||
class RenderProcessor : public NodeTraverser
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static void Process(RenderTicketPtr ticket, Renderer* render_ctx);
|
||||
static void Process(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache);
|
||||
|
||||
struct RenderedWaveform {
|
||||
const TrackOutput* track;
|
||||
@@ -40,11 +40,6 @@ public:
|
||||
TimeRange range;
|
||||
};
|
||||
|
||||
signals:
|
||||
void GeneratedFrame(FramePtr frame);
|
||||
|
||||
void GeneratedAudio(SampleBufferPtr audio);
|
||||
|
||||
protected:
|
||||
virtual NodeValueTable GenerateBlockTable(const TrackOutput *track, const TimeRange &range) override;
|
||||
|
||||
@@ -61,16 +56,20 @@ protected:
|
||||
virtual QVariant GetCachedFrame(const Node *node, const rational &time) override;
|
||||
|
||||
private:
|
||||
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx);
|
||||
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache);
|
||||
|
||||
void Run();
|
||||
|
||||
DecoderPtr ResolveDecoderFromInput(StreamPtr stream);
|
||||
|
||||
RenderTicketPtr ticket_;
|
||||
|
||||
Renderer* render_ctx_;
|
||||
|
||||
StillImageCache* still_image_cache_;
|
||||
|
||||
DecoderCache* decoder_cache_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -43,51 +43,90 @@ public:
|
||||
const PixelFormat::Format& format, const rational& pixel_aspect_ratio = 1,
|
||||
const Interlacing& interlacing = kInterlaceNone, const int& divider = 1);
|
||||
|
||||
const int& width() const
|
||||
int width() const
|
||||
{
|
||||
return width_;
|
||||
}
|
||||
|
||||
const int& height() const
|
||||
void set_width(int width)
|
||||
{
|
||||
width_ = width;
|
||||
calculate_effective_size();
|
||||
}
|
||||
|
||||
int height() const
|
||||
{
|
||||
return height_;
|
||||
}
|
||||
|
||||
void set_height(int height)
|
||||
{
|
||||
height_ = height;
|
||||
calculate_effective_size();
|
||||
}
|
||||
|
||||
const rational& time_base() const
|
||||
{
|
||||
return time_base_;
|
||||
}
|
||||
|
||||
const int& divider() const
|
||||
void set_time_base(const rational& r)
|
||||
{
|
||||
time_base_ = r;
|
||||
}
|
||||
|
||||
int divider() const
|
||||
{
|
||||
return divider_;
|
||||
}
|
||||
|
||||
const int& effective_width() const
|
||||
void set_divider(int d)
|
||||
{
|
||||
divider_ = d;
|
||||
calculate_effective_size();
|
||||
}
|
||||
|
||||
int effective_width() const
|
||||
{
|
||||
return effective_width_;
|
||||
}
|
||||
|
||||
const int& effective_height() const
|
||||
int effective_height() const
|
||||
{
|
||||
return effective_height_;
|
||||
}
|
||||
|
||||
const PixelFormat::Format& format() const
|
||||
PixelFormat::Format format() const
|
||||
{
|
||||
return format_;
|
||||
}
|
||||
|
||||
void set_format(PixelFormat::Format f)
|
||||
{
|
||||
format_ = f;
|
||||
}
|
||||
|
||||
const rational& pixel_aspect_ratio() const
|
||||
{
|
||||
return pixel_aspect_ratio_;
|
||||
}
|
||||
|
||||
void set_pixel_aspect_ratio(const rational& r)
|
||||
{
|
||||
pixel_aspect_ratio_ = r;
|
||||
validate_pixel_aspect_ratio();
|
||||
}
|
||||
|
||||
Interlacing interlacing() const
|
||||
{
|
||||
return interlacing_;
|
||||
}
|
||||
|
||||
void set_interlacing(Interlacing i)
|
||||
{
|
||||
interlacing_ = i;
|
||||
}
|
||||
|
||||
static int generate_auto_divider(qint64 width, qint64 height);
|
||||
|
||||
bool is_valid() const;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D ove_maintex;
|
||||
uniform vec2 ove_resolution;
|
||||
uniform vec2 ove_viewport;
|
||||
|
||||
uniform vec2 viewport;
|
||||
uniform float histogram_scale;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
@@ -11,7 +9,7 @@ in vec2 ove_texcoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main(void) {
|
||||
float histogram_width = ceil(histogram_scale * ove_viewport.y);
|
||||
float histogram_width = ceil(histogram_scale * viewport.y);
|
||||
float quantisation = 1.0 / (histogram_width - 1.0);
|
||||
vec3 cur_col = vec3(0.0);
|
||||
vec3 sum = vec3(0.0);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#version 150
|
||||
|
||||
uniform float histogram_scale;
|
||||
uniform vec2 ove_resolution;
|
||||
|
||||
in vec4 a_position;
|
||||
in vec2 a_texcoord;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D ove_maintex;
|
||||
uniform vec2 ove_resolution;
|
||||
uniform vec2 ove_viewport;
|
||||
uniform vec2 viewport;
|
||||
|
||||
uniform float histogram_scale;
|
||||
uniform float histogram_power;
|
||||
@@ -13,11 +12,11 @@ out vec4 fragColor;
|
||||
|
||||
void main(void) {
|
||||
vec3 col = vec3(0.0);
|
||||
float histogram_height = ceil(ove_viewport.y * histogram_scale);
|
||||
float histogram_height = ceil(viewport.y * histogram_scale);
|
||||
vec3 histogram_ratio = vec3(0.0);
|
||||
vec3 sum = vec3(0.0);
|
||||
float ratio = 0.0;
|
||||
vec3 total_pixels = vec3(ceil(ove_viewport.x * ove_resolution.y *
|
||||
vec3 total_pixels = vec3(ceil(viewport.x * viewport.y *
|
||||
histogram_scale));
|
||||
|
||||
for (int i = 0; i < histogram_height; i++) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D ove_maintex;
|
||||
uniform vec2 ove_resolution;
|
||||
uniform vec2 ove_viewport;
|
||||
|
||||
uniform vec2 viewport;
|
||||
uniform vec3 luma_coeffs;
|
||||
|
||||
uniform float waveform_scale;
|
||||
@@ -12,7 +12,7 @@ in vec2 ove_texcoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main(void) {
|
||||
float waveform_height = ceil(waveform_scale * ove_viewport.y);
|
||||
float waveform_height = ceil(waveform_scale * viewport.y);
|
||||
float quantisation = 1.0 / (waveform_height - 1.0);
|
||||
float intensity = 0.10;
|
||||
vec4 col = vec4(0.0);
|
||||
|
||||
@@ -33,7 +33,10 @@ ConformTask::ConformTask(AudioStreamPtr stream, const AudioParams& params) :
|
||||
|
||||
bool ConformTask::Run()
|
||||
{
|
||||
if (stream_->footage()->decoder().isEmpty()) {
|
||||
// Conforming is done by the renderer now, but I would like to use something like this just to
|
||||
// show progress
|
||||
|
||||
/*if (stream_->footage()->decoder().isEmpty()) {
|
||||
SetError(tr("Failed to find decoder to conform audio stream"));
|
||||
return false;
|
||||
} else {
|
||||
@@ -49,7 +52,9 @@ bool ConformTask::Run()
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -115,17 +115,8 @@ bool ExportTask::Run()
|
||||
void FrameColorConvert(ColorProcessorPtr processor, FramePtr frame)
|
||||
{
|
||||
// OCIO conversion requires a frame in 32F format
|
||||
if (frame->format() != PixelFormat::PIX_FMT_RGBA32F
|
||||
&& frame->format() != PixelFormat::PIX_FMT_RGB32F) {
|
||||
PixelFormat::Format dst;
|
||||
|
||||
if (PixelFormat::FormatHasAlphaChannel(frame->format())) {
|
||||
dst = PixelFormat::PIX_FMT_RGBA32F;
|
||||
} else {
|
||||
dst = PixelFormat::PIX_FMT_RGB32F;
|
||||
}
|
||||
|
||||
frame = PixelFormat::ConvertPixelFormat(frame, dst);
|
||||
if (frame->format() != PixelFormat::PIX_FMT_RGBA32F) {
|
||||
frame = PixelFormat::ConvertPixelFormat(frame, PixelFormat::PIX_FMT_RGBA32F);
|
||||
}
|
||||
|
||||
// Color conversion must be done with unassociated alpha, and the pipeline is always associated
|
||||
|
||||
@@ -110,7 +110,7 @@ void ProjectImportTask::Import(Folder *folder, QFileInfoList import, int &counte
|
||||
|
||||
} else {
|
||||
|
||||
FootagePtr item = Decoder::ProbeMedia(model_->project(), file_info.absoluteFilePath(),
|
||||
FootagePtr item = Decoder::Probe(model_->project(), file_info.absoluteFilePath(),
|
||||
&IsCancelled());
|
||||
|
||||
if (item) {
|
||||
|
||||
@@ -52,8 +52,6 @@ ThreadPool::~ThreadPool()
|
||||
thread->wait();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
RunNext();
|
||||
}
|
||||
|
||||
void ThreadPool::AddTicket(RenderTicketPtr ticket, bool prioritize)
|
||||
|
||||
@@ -83,7 +83,12 @@ void RenderTicket::Finish(QVariant result, bool cancelled)
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
|
||||
if (started_ && !finished_) {
|
||||
if (!started_) {
|
||||
qWarning() << "Tried to finish a ticket that hadn't started";
|
||||
} else if (finished_) {
|
||||
// Do nothing
|
||||
return;
|
||||
} else {
|
||||
finished_ = true;
|
||||
cancelled_ = cancelled;
|
||||
|
||||
|
||||
@@ -30,8 +30,15 @@ RenderTicketWatcher::RenderTicketWatcher(QObject *parent) :
|
||||
|
||||
void RenderTicketWatcher::SetTicket(RenderTicketPtr ticket)
|
||||
{
|
||||
// Ensure that a ticket has NOT already been set and that this ticket is NOT NULL
|
||||
Q_ASSERT(!ticket_ && ticket);
|
||||
if (ticket_) {
|
||||
qCritical() << "Tried to set a ticket on a RenderTicketWatcher twice";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ticket) {
|
||||
qCritical() << "Tried to set a null ticket on a RenderTicketWatcher";
|
||||
return;
|
||||
}
|
||||
|
||||
ticket_ = ticket;
|
||||
|
||||
|
||||
@@ -20,25 +20,59 @@
|
||||
|
||||
#include "manageddisplay.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "render/backend/opengl/openglrenderer.h"
|
||||
#include "render/rendermanager.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
ManagedDisplayWidget::ManagedDisplayWidget(QWidget *parent) :
|
||||
QOpenGLWidget(parent),
|
||||
QWidget(parent),
|
||||
color_manager_(nullptr),
|
||||
color_service_(nullptr)
|
||||
{
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
attached_renderer_ = new OpenGLRenderer();
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->setSpacing(0);
|
||||
layout->setMargin(0);
|
||||
|
||||
if (RenderManager::instance()->backend() == RenderManager::kOpenGL) {
|
||||
// Create OpenGL widget
|
||||
inner_widget_ = new ManagedDisplayWidgetOpenGL();
|
||||
connect(static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_),
|
||||
&ManagedDisplayWidgetOpenGL::OnInit,
|
||||
this, &ManagedDisplayWidget::OnInit, Qt::DirectConnection);
|
||||
connect(static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_),
|
||||
&ManagedDisplayWidgetOpenGL::OnDestroy,
|
||||
this, &ManagedDisplayWidget::OnDestroy, Qt::DirectConnection);
|
||||
connect(static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_),
|
||||
&ManagedDisplayWidgetOpenGL::OnPaint,
|
||||
this, &ManagedDisplayWidget::OnPaint, Qt::DirectConnection);
|
||||
connect(static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_),
|
||||
&ManagedDisplayWidgetOpenGL::frameSwapped,
|
||||
this, &ManagedDisplayWidget::frameSwapped, Qt::DirectConnection);
|
||||
|
||||
// Create OpenGL renderer
|
||||
attached_renderer_ = new OpenGLRenderer(this);
|
||||
} else {
|
||||
inner_widget_ = nullptr;
|
||||
}
|
||||
|
||||
layout->addWidget(inner_widget_);
|
||||
}
|
||||
|
||||
ManagedDisplayWidget::~ManagedDisplayWidget()
|
||||
{
|
||||
ContextCleanup();
|
||||
OnDestroy();
|
||||
|
||||
if (RenderManager::instance()->backend() == RenderManager::kOpenGL) {
|
||||
disconnect(static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_),
|
||||
&ManagedDisplayWidgetOpenGL::OnDestroy,
|
||||
this, &ManagedDisplayWidget::OnDestroy);
|
||||
}
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::ConnectColorManager(ColorManager *color_manager)
|
||||
@@ -111,17 +145,6 @@ ColorProcessorPtr ManagedDisplayWidget::color_service()
|
||||
return color_service_;
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::ContextCleanup()
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
color_service_ = nullptr;
|
||||
|
||||
attached_renderer_->Destroy();
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::ShowDefaultContextMenu()
|
||||
{
|
||||
Menu m(this);
|
||||
@@ -178,24 +201,27 @@ void ManagedDisplayWidget::MenuColorspaceSelect(QAction *action)
|
||||
SetColorTransform(color_manager()->GetCompliantColorSpace(ColorTransform(action->data().toString())));
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::SetColorTransform(const ColorTransform &transform)
|
||||
void ManagedDisplayWidget::OnDestroy()
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
color_transform_ = transform;
|
||||
SetupColorProcessor();
|
||||
ColorProcessorChangedEvent();
|
||||
|
||||
doneCurrent();
|
||||
attached_renderer_->Destroy();
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::initializeGL()
|
||||
void ManagedDisplayWidget::SetColorTransform(const ColorTransform &transform)
|
||||
{
|
||||
color_transform_ = transform;
|
||||
|
||||
SetupColorProcessor();
|
||||
|
||||
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ManagedDisplayWidget::ContextCleanup, Qt::DirectConnection);
|
||||
ColorProcessorChangedEvent();
|
||||
}
|
||||
|
||||
static_cast<OpenGLRenderer*>(attached_renderer_)->Init(context());
|
||||
void ManagedDisplayWidget::OnInit()
|
||||
{
|
||||
if (RenderManager::instance()->backend() == RenderManager::kOpenGL) {
|
||||
QOpenGLContext* context = static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_)->context();
|
||||
static_cast<OpenGLRenderer*>(attached_renderer_)->Init(context);
|
||||
static_cast<OpenGLRenderer*>(attached_renderer_)->PostInit();
|
||||
}
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::EnableDefaultContextMenu()
|
||||
@@ -208,6 +234,20 @@ void ManagedDisplayWidget::ColorProcessorChangedEvent()
|
||||
update();
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::makeCurrent()
|
||||
{
|
||||
if (RenderManager::instance()->backend() == RenderManager::kOpenGL) {
|
||||
static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_)->makeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::doneCurrent()
|
||||
{
|
||||
if (RenderManager::instance()->backend() == RenderManager::kOpenGL) {
|
||||
static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_)->doneCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
Menu* ManagedDisplayWidget::GetDisplayMenu(QMenu* parent, bool auto_connect)
|
||||
{
|
||||
QStringList displays = color_manager()->ListAvailableDisplays();
|
||||
@@ -277,35 +317,25 @@ Menu* ManagedDisplayWidget::GetLookMenu(QMenu* parent, bool auto_connect)
|
||||
|
||||
void ManagedDisplayWidget::SetupColorProcessor()
|
||||
{
|
||||
if (!context()) {
|
||||
return;
|
||||
}
|
||||
|
||||
color_service_ = nullptr;
|
||||
|
||||
if (color_manager_) {
|
||||
// (Re)create color processor
|
||||
|
||||
try {
|
||||
|
||||
color_service_ = ColorProcessor::Create(color_manager_,
|
||||
color_manager_->GetReferenceColorSpace(),
|
||||
color_transform_);
|
||||
|
||||
} catch (OCIO::Exception& e) {
|
||||
|
||||
QMessageBox::critical(this,
|
||||
tr("OpenColorIO Error"),
|
||||
tr("Failed to set color configuration: %1").arg(e.what()),
|
||||
QMessageBox::Ok);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
color_service_ = nullptr;
|
||||
}
|
||||
|
||||
emit ColorProcessorChanged(std::static_pointer_cast<ColorProcessor>(color_service_));
|
||||
emit ColorProcessorChanged(color_service_);
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -29,7 +29,49 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class ManagedDisplayWidget : public QOpenGLWidget
|
||||
class ManagedDisplayWidgetOpenGL : public QOpenGLWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ManagedDisplayWidgetOpenGL(QWidget* parent = nullptr) :
|
||||
QOpenGLWidget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
signals:
|
||||
void OnInit();
|
||||
|
||||
void OnPaint();
|
||||
|
||||
void OnDestroy();
|
||||
|
||||
protected:
|
||||
virtual void initializeGL() override
|
||||
{
|
||||
connect(context(), &QOpenGLContext::aboutToBeDestroyed,
|
||||
this, &ManagedDisplayWidgetOpenGL::OnDestroy);
|
||||
|
||||
emit OnInit();
|
||||
}
|
||||
|
||||
virtual void paintGL() override
|
||||
{
|
||||
emit OnPaint();
|
||||
}
|
||||
|
||||
private slots:
|
||||
void DestroyListener()
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
emit OnDestroy();
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class ManagedDisplayWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -94,17 +136,14 @@ signals:
|
||||
*/
|
||||
void ColorManagerChanged(ColorManager* color_manager);
|
||||
|
||||
void frameSwapped();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Provides access to the color processor (nullptr if none is set)
|
||||
*/
|
||||
ColorProcessorPtr color_service();
|
||||
|
||||
/**
|
||||
* @brief Override when setting up OpenGL context
|
||||
*/
|
||||
virtual void initializeGL() override;
|
||||
|
||||
/**
|
||||
* @brief Enables a context menu that allows simple access to the DVL pipeline
|
||||
*/
|
||||
@@ -117,6 +156,31 @@ protected:
|
||||
*/
|
||||
virtual void ColorProcessorChangedEvent();
|
||||
|
||||
Renderer* renderer() const
|
||||
{
|
||||
return attached_renderer_;
|
||||
}
|
||||
|
||||
void makeCurrent();
|
||||
|
||||
void doneCurrent();
|
||||
|
||||
protected slots:
|
||||
/**
|
||||
* @brief Called whenever the internal rendering context has been created
|
||||
*/
|
||||
virtual void OnInit();
|
||||
|
||||
/**
|
||||
* @brief Called while the internal rendering context is being rendered
|
||||
*/
|
||||
virtual void OnPaint() = 0;
|
||||
|
||||
/**
|
||||
* @brief Called just before the internal rendering context is destroyed
|
||||
*/
|
||||
virtual void OnDestroy();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Call this if this user has selected a different display/view/look to recreate the processor
|
||||
@@ -128,6 +192,11 @@ private:
|
||||
*/
|
||||
void ClearOCIOLutTexture();
|
||||
|
||||
/**
|
||||
* @brief Main drawing surface abstraction
|
||||
*/
|
||||
QWidget* inner_widget_;
|
||||
|
||||
/**
|
||||
* @brief Renderer abstraction
|
||||
*/
|
||||
@@ -154,11 +223,6 @@ private slots:
|
||||
*/
|
||||
void ColorConfigChanged();
|
||||
|
||||
/**
|
||||
* @brief Cleans up resources if context is about to be destroyed
|
||||
*/
|
||||
void ContextCleanup();
|
||||
|
||||
/**
|
||||
* @brief The default context menu shown
|
||||
*/
|
||||
|
||||
@@ -145,10 +145,7 @@ void NodeTableView::SetTime(const rational &time)
|
||||
case NodeParam::kTexture:
|
||||
{
|
||||
// NodeTableTraverser puts video params in here
|
||||
VideoParams p = value.data().value<VideoParams>();
|
||||
int channel_count = PixelFormat::ChannelCount(p.format());
|
||||
|
||||
for (int k=0;k<channel_count;k++) {
|
||||
for (int k=0;k<kRGBAChannels;k++) {
|
||||
this->setItemWidget(sub_item, 2 + k, new QCheckBox());
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <QPainter>
|
||||
#include <QtMath>
|
||||
#include <QVector2D>
|
||||
|
||||
#include "common/qtutils.h"
|
||||
#include "node/node.h"
|
||||
@@ -35,74 +36,33 @@ HistogramScope::HistogramScope(QWidget* parent) :
|
||||
|
||||
HistogramScope::~HistogramScope()
|
||||
{
|
||||
CleanUp();
|
||||
|
||||
if (context()) {
|
||||
disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this,
|
||||
&HistogramScope::CleanUp);
|
||||
}
|
||||
OnDestroy();
|
||||
}
|
||||
|
||||
void HistogramScope::initializeGL()
|
||||
void HistogramScope::OnInit()
|
||||
{
|
||||
ScopeBase::initializeGL();
|
||||
ScopeBase::OnInit();
|
||||
|
||||
pipeline_secondary_ = CreateSecondaryShader();
|
||||
|
||||
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this,
|
||||
&HistogramScope::CleanUp, Qt::DirectConnection);
|
||||
}
|
||||
|
||||
void HistogramScope::AssertAdditionalTextures()
|
||||
{
|
||||
if (!texture_row_sums_.IsCreated()
|
||||
|| texture_row_sums_.width() != width()
|
||||
|| texture_row_sums_.height() != height()) {
|
||||
texture_row_sums_.Destroy();
|
||||
texture_row_sums_.Create(context(), VideoParams(width(),
|
||||
height(), managed_tex().format()));
|
||||
}
|
||||
}
|
||||
|
||||
void HistogramScope::CleanUp()
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
pipeline_secondary_ = nullptr;
|
||||
texture_row_sums_.Destroy();
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
QVariant HistogramScope::CreateShader()
|
||||
{
|
||||
OpenGLShaderPtr pipeline = OpenGLShader::Create();
|
||||
|
||||
pipeline->create();
|
||||
pipeline->addShaderFromSourceCode(QOpenGLShader::Vertex,
|
||||
OpenGLShader::CodeDefaultVertex());
|
||||
pipeline->addShaderFromSourceCode(QOpenGLShader::Fragment,
|
||||
Node::ReadFileAsString(":/shaders/rgbhistogram.frag"));
|
||||
pipeline->link();
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
OpenGLShaderPtr HistogramScope::CreateSecondaryShader()
|
||||
{
|
||||
OpenGLShaderPtr shader = OpenGLShader::Create();
|
||||
|
||||
shader->create();
|
||||
shader->addShaderFromSourceCode(QOpenGLShader::Vertex,
|
||||
ShaderCode secondary_code(Node::ReadFileAsString(":/shaders/rgbhistogram_secondary.frag"),
|
||||
Node::ReadFileAsString(":/shaders/rgbhistogram.vert"));
|
||||
shader->addShaderFromSourceCode(QOpenGLShader::Fragment,
|
||||
Node::ReadFileAsString(":/shaders/rgbhistogram_secondary.frag"));
|
||||
shader->link();
|
||||
|
||||
return shader;
|
||||
pipeline_secondary_ = renderer()->CreateNativeShader(secondary_code);
|
||||
}
|
||||
|
||||
void HistogramScope::DrawScope()
|
||||
void HistogramScope::OnDestroy()
|
||||
{
|
||||
ScopeBase::OnDestroy();
|
||||
|
||||
pipeline_secondary_.clear();
|
||||
texture_row_sums_ = nullptr;
|
||||
}
|
||||
|
||||
ShaderCode HistogramScope::GenerateShaderCode()
|
||||
{
|
||||
return ShaderCode(Node::ReadFileAsString(":/shaders/rgbhistogram.frag"),
|
||||
Node::ReadFileAsString(":/shaders/default.vert"));
|
||||
}
|
||||
|
||||
void HistogramScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline)
|
||||
{
|
||||
float histogram_scale = 0.80f;
|
||||
// This value is eyeballed for usefulness. Until we have a geometry
|
||||
@@ -111,40 +71,21 @@ void HistogramScope::DrawScope()
|
||||
float histogram_base = 2.5f;
|
||||
float histogram_power = 1.0f / histogram_base;
|
||||
|
||||
pipeline()->bind();
|
||||
pipeline()->setUniformValue("ove_resolution", managed_tex().width(),
|
||||
managed_tex().height());
|
||||
pipeline()->setUniformValue("ove_viewport", width(), height());
|
||||
pipeline()->setUniformValue("histogram_scale", histogram_scale);
|
||||
pipeline()->release();
|
||||
Renderer::ShaderUniformMap value_map;
|
||||
|
||||
AssertAdditionalTextures();
|
||||
value_map.insert(QStringLiteral("viewport"), {QVector2D(width(), height()), NodeParam::kVec2});
|
||||
value_map.insert(QStringLiteral("histogram_scale"), {histogram_scale, NodeParam::kFloat});
|
||||
value_map.insert(QStringLiteral("histogram_power"), {histogram_power, NodeParam::kFloat});
|
||||
|
||||
framebuffer().Attach(&texture_row_sums_, true);
|
||||
framebuffer().Bind();
|
||||
if (!texture_row_sums_
|
||||
|| texture_row_sums_->width() != this->width()
|
||||
|| texture_row_sums_->height() != this->height()) {
|
||||
texture_row_sums_ = renderer()->CreateTexture(VideoParams(width(), height(), managed_tex->format()));
|
||||
}
|
||||
|
||||
managed_tex().Bind();
|
||||
renderer()->Blit(managed_tex.get(), pipeline, value_map, texture_row_sums_.get());
|
||||
|
||||
OpenGLRenderFunctions::Blit(pipeline());
|
||||
|
||||
managed_tex().Release();
|
||||
|
||||
framebuffer().Release();
|
||||
framebuffer().Detach();
|
||||
|
||||
pipeline_secondary_->bind();
|
||||
pipeline_secondary_->setUniformValue("ove_resolution",
|
||||
texture_row_sums_.width(), texture_row_sums_.height());
|
||||
pipeline_secondary_->setUniformValue("ove_viewport", width(), height());
|
||||
pipeline_secondary_->setUniformValue("histogram_scale", histogram_scale);
|
||||
pipeline_secondary_->setUniformValue("histogram_power", histogram_power);
|
||||
pipeline_secondary_->release();
|
||||
|
||||
texture_row_sums_.Bind();
|
||||
|
||||
OpenGLRenderFunctions::Blit(pipeline_secondary_);
|
||||
|
||||
texture_row_sums_.Release();
|
||||
renderer()->Blit(texture_row_sums_.get(), pipeline_secondary_, value_map);
|
||||
|
||||
// Draw line overlays
|
||||
QPainter p(this);
|
||||
|
||||
@@ -33,22 +33,21 @@ public:
|
||||
|
||||
virtual ~HistogramScope() override;
|
||||
|
||||
protected:
|
||||
virtual void initializeGL() override;
|
||||
protected slots:
|
||||
virtual void OnInit() override;
|
||||
|
||||
virtual QVariant CreateShader() override;
|
||||
virtual void OnDestroy() override;
|
||||
|
||||
protected:
|
||||
virtual ShaderCode GenerateShaderCode() override;
|
||||
QVariant CreateSecondaryShader();
|
||||
|
||||
void AssertAdditionalTextures();
|
||||
|
||||
virtual void DrawScope() override;
|
||||
virtual void DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline) override;
|
||||
|
||||
private:
|
||||
QVariant pipeline_secondary_;
|
||||
QVariant texture_row_sums_;
|
||||
Renderer::TexturePtr texture_row_sums_;
|
||||
|
||||
private slots:
|
||||
void CleanUp();
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
|
||||
#include "scopebase.h"
|
||||
|
||||
#include "render/backend/opengl/openglrenderfunctions.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
ScopeBase::ScopeBase(QWidget* parent) :
|
||||
@@ -33,11 +31,7 @@ ScopeBase::ScopeBase(QWidget* parent) :
|
||||
|
||||
ScopeBase::~ScopeBase()
|
||||
{
|
||||
CleanUp();
|
||||
|
||||
if (context()) {
|
||||
disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ScopeBase::CleanUp);
|
||||
}
|
||||
OnDestroy();
|
||||
}
|
||||
|
||||
void ScopeBase::SetBuffer(Frame *frame)
|
||||
@@ -54,18 +48,9 @@ void ScopeBase::showEvent(QShowEvent* e)
|
||||
UploadTextureFromBuffer();
|
||||
}
|
||||
|
||||
QVariant ScopeBase::CreateShader()
|
||||
void ScopeBase::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline)
|
||||
{
|
||||
return OpenGLShader::CreateDefault();
|
||||
}
|
||||
|
||||
void ScopeBase::DrawScope()
|
||||
{
|
||||
managed_tex().Bind();
|
||||
|
||||
OpenGLRenderFunctions::Blit(pipeline());
|
||||
|
||||
managed_tex().Release();
|
||||
renderer()->Blit(managed_tex.get(), pipeline, Renderer::ShaderUniformMap());
|
||||
}
|
||||
|
||||
void ScopeBase::UploadTextureFromBuffer()
|
||||
@@ -77,17 +62,18 @@ void ScopeBase::UploadTextureFromBuffer()
|
||||
if (buffer_) {
|
||||
makeCurrent();
|
||||
|
||||
if (!texture_.IsCreated()
|
||||
|| texture_.width() != buffer_->width()
|
||||
|| texture_.height() != buffer_->height()
|
||||
|| texture_.format() != buffer_->format()) {
|
||||
texture_.Destroy();
|
||||
managed_tex_.Destroy();
|
||||
if (!texture_
|
||||
|| texture_->width() != buffer_->width()
|
||||
|| texture_->height() != buffer_->height()
|
||||
|| texture_->format() != buffer_->format()) {
|
||||
texture_ = nullptr;
|
||||
managed_tex_ = nullptr;
|
||||
|
||||
texture_.Create(context(), buffer_);
|
||||
managed_tex_.Create(context(), buffer_->video_params());
|
||||
texture_ = renderer()->CreateTexture(buffer_->video_params(),
|
||||
buffer_->data(), buffer_->linesize_pixels());
|
||||
managed_tex_ = renderer()->CreateTexture(buffer_->video_params());
|
||||
} else {
|
||||
texture_.Upload(buffer_);
|
||||
texture_->Upload(buffer_->data(), buffer_->linesize_pixels());
|
||||
}
|
||||
|
||||
doneCurrent();
|
||||
@@ -96,58 +82,36 @@ void ScopeBase::UploadTextureFromBuffer()
|
||||
update();
|
||||
}
|
||||
|
||||
void ScopeBase::CleanUp()
|
||||
void ScopeBase::OnInit()
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
pipeline_ = nullptr;
|
||||
texture_.Destroy();
|
||||
managed_tex_.Destroy();
|
||||
framebuffer_.Destroy();
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
void ScopeBase::initializeGL()
|
||||
{
|
||||
ManagedDisplayWidget::initializeGL();
|
||||
|
||||
pipeline_ = CreateShader();
|
||||
|
||||
framebuffer_.Create(context());
|
||||
|
||||
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ScopeBase::CleanUp, Qt::DirectConnection);
|
||||
ManagedDisplayWidget::OnInit();
|
||||
|
||||
UploadTextureFromBuffer();
|
||||
|
||||
pipeline_ = renderer()->CreateNativeShader(GenerateShaderCode());
|
||||
}
|
||||
|
||||
void ScopeBase::paintGL()
|
||||
void ScopeBase::OnPaint()
|
||||
{
|
||||
QOpenGLFunctions* f = context()->functions();
|
||||
// Clear display surface
|
||||
renderer()->ClearDestination();
|
||||
|
||||
f->glClearColor(0, 0, 0, 0);
|
||||
f->glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
if (buffer_ && pipeline() && texture_.IsCreated()) {
|
||||
if (buffer_) {
|
||||
// Convert reference frame to display space
|
||||
framebuffer_.Attach(&managed_tex_);
|
||||
framebuffer_.Bind();
|
||||
renderer()->BlitColorManaged(color_service(), texture_.get(), managed_tex_.get());
|
||||
|
||||
texture_.Bind();
|
||||
|
||||
f->glViewport(0, 0, texture_.width(), texture_.height());
|
||||
|
||||
color_service()->ProcessOpenGL();
|
||||
|
||||
texture_.Release();
|
||||
|
||||
framebuffer_.Release();
|
||||
framebuffer_.Detach();
|
||||
|
||||
f->glViewport(0, 0, width(), height());
|
||||
|
||||
DrawScope();
|
||||
renderer()->SetViewport(width(), height());
|
||||
DrawScope(managed_tex_, pipeline_);
|
||||
}
|
||||
}
|
||||
|
||||
void ScopeBase::OnDestroy()
|
||||
{
|
||||
ManagedDisplayWidget::OnDestroy();
|
||||
|
||||
managed_tex_ = nullptr;
|
||||
texture_ = nullptr;
|
||||
pipeline_.clear();
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -37,41 +37,36 @@ public:
|
||||
public slots:
|
||||
void SetBuffer(Frame* frame);
|
||||
|
||||
protected slots:
|
||||
virtual void OnInit() override;
|
||||
|
||||
virtual void OnPaint() override;
|
||||
|
||||
virtual void OnDestroy() override;
|
||||
|
||||
protected:
|
||||
virtual void initializeGL() override;
|
||||
|
||||
virtual void paintGL() override;
|
||||
|
||||
virtual void showEvent(QShowEvent* e) override;
|
||||
|
||||
virtual QVariant CreateShader();
|
||||
virtual ShaderCode GenerateShaderCode() = 0;
|
||||
|
||||
virtual void DrawScope();
|
||||
|
||||
QVariant pipeline()
|
||||
{
|
||||
return pipeline_;
|
||||
}
|
||||
|
||||
QVariant managed_tex()
|
||||
{
|
||||
return managed_tex_;
|
||||
}
|
||||
/**
|
||||
* @brief Draw function
|
||||
*
|
||||
* Override this if your sub-class scope needs extra drawing.
|
||||
*/
|
||||
virtual void DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline);
|
||||
|
||||
private:
|
||||
void UploadTextureFromBuffer();
|
||||
|
||||
QVariant pipeline_;
|
||||
|
||||
QVariant texture_;
|
||||
Renderer::TexturePtr texture_;
|
||||
|
||||
QVariant managed_tex_;
|
||||
Renderer::TexturePtr managed_tex_;
|
||||
|
||||
Frame* buffer_;
|
||||
|
||||
private slots:
|
||||
void CleanUp();
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -24,10 +24,11 @@
|
||||
#include <QPainter>
|
||||
#include <QtMath>
|
||||
#include <QDebug>
|
||||
#include <QVector2D>
|
||||
#include <QVector3D>
|
||||
|
||||
#include "common/qtutils.h"
|
||||
#include "node/node.h"
|
||||
#include "render/backend/opengl/openglrenderfunctions.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
@@ -36,42 +37,39 @@ WaveformScope::WaveformScope(QWidget* parent) :
|
||||
{
|
||||
}
|
||||
|
||||
QVariant WaveformScope::CreateShader()
|
||||
WaveformScope::~WaveformScope()
|
||||
{
|
||||
OpenGLShaderPtr pipeline = OpenGLShader::Create();
|
||||
|
||||
pipeline->create();
|
||||
pipeline->addShaderFromSourceCode(QOpenGLShader::Vertex,
|
||||
Node::ReadFileAsString(":/shaders/rgbwaveform.vert"));
|
||||
pipeline->addShaderFromSourceCode(QOpenGLShader::Fragment,
|
||||
Node::ReadFileAsString(":/shaders/rgbwaveform.frag"));
|
||||
pipeline->link();
|
||||
|
||||
return pipeline;
|
||||
OnDestroy();
|
||||
}
|
||||
|
||||
void WaveformScope::DrawScope()
|
||||
ShaderCode WaveformScope::GenerateShaderCode()
|
||||
{
|
||||
return ShaderCode(Node::ReadFileAsString(":/shaders/rgbwaveform.frag"),
|
||||
Node::ReadFileAsString(":/shaders/rgbwaveform.vert"));
|
||||
}
|
||||
|
||||
void WaveformScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline)
|
||||
{
|
||||
float waveform_scale = 0.80f;
|
||||
|
||||
// Draw waveform through shader
|
||||
pipeline()->bind();
|
||||
pipeline()->setUniformValue("ove_resolution", managed_tex().width(), managed_tex().height());
|
||||
pipeline()->setUniformValue("ove_viewport", width(), height());
|
||||
GLfloat luma[3] = {0.0, 0.0, 0.0};
|
||||
color_manager()->GetDefaultLumaCoefs(luma);
|
||||
pipeline()->setUniformValue("luma_coeffs", luma[0], luma[1], luma[2]);
|
||||
Renderer::ShaderUniformMap value_map;
|
||||
|
||||
// Set viewport size
|
||||
value_map.insert(QStringLiteral("viewport"),
|
||||
{QVector2D(width(), height()), NodeParam::kVec2});
|
||||
|
||||
// Set luma coefficients
|
||||
float luma_coeffs[3] = {0.0f, 0.0f, 0.0f};
|
||||
color_manager()->GetDefaultLumaCoefs(luma_coeffs);
|
||||
value_map.insert(QStringLiteral("luma_coeffs"),
|
||||
{QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]), NodeParam::kVec3});
|
||||
|
||||
|
||||
// Scale of the waveform relative to the viewport surface.
|
||||
pipeline()->setUniformValue("waveform_scale", waveform_scale);
|
||||
value_map.insert(QStringLiteral("waveform_scale"), {waveform_scale, NodeParam::kFloat});
|
||||
|
||||
pipeline()->release();
|
||||
|
||||
managed_tex().Bind();
|
||||
|
||||
OpenGLRenderFunctions::Blit(pipeline());
|
||||
|
||||
managed_tex().Release();
|
||||
renderer()->Blit(managed_tex.get(), pipeline, value_map);
|
||||
|
||||
float waveform_dim_x = ceil((width() - 1.0) * waveform_scale);
|
||||
float waveform_dim_y = ceil((height() - 1.0) * waveform_scale);
|
||||
@@ -112,6 +110,7 @@ void WaveformScope::DrawScope()
|
||||
(waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y + font_y_offset,
|
||||
label);
|
||||
}
|
||||
|
||||
p.drawLines(ire_lines);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,10 +31,12 @@ class WaveformScope : public ScopeBase
|
||||
public:
|
||||
WaveformScope(QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
virtual QVariant CreateShader() override;
|
||||
virtual ~WaveformScope() override;
|
||||
|
||||
virtual void DrawScope() override;
|
||||
protected:
|
||||
virtual ShaderCode GenerateShaderCode() override;
|
||||
|
||||
virtual void DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -31,15 +31,14 @@ class PixelFormatComboBox : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PixelFormatComboBox(bool alpha_only, bool float_only, QWidget* parent = nullptr) :
|
||||
PixelFormatComboBox(bool float_only, QWidget* parent = nullptr) :
|
||||
QComboBox(parent)
|
||||
{
|
||||
// Set up preview formats
|
||||
for (int i=0;i<PixelFormat::PIX_FMT_COUNT;i++) {
|
||||
PixelFormat::Format pix_fmt = static_cast<PixelFormat::Format>(i);
|
||||
|
||||
if ((!alpha_only || PixelFormat::FormatHasAlphaChannel(pix_fmt))
|
||||
&& (!float_only || PixelFormat::FormatIsFloat(pix_fmt))) {
|
||||
if (!float_only || PixelFormat::FormatIsFloat(pix_fmt)) {
|
||||
this->addItem(PixelFormat::GetName(pix_fmt), pix_fmt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@
|
||||
#include "common/define.h"
|
||||
#include "common/functiontimer.h"
|
||||
#include "gizmotraverser.h"
|
||||
#include "render/backend/opengl/openglrenderfunctions.h"
|
||||
#include "render/backend/opengl/openglshader.h"
|
||||
#include "render/pixelformat.h"
|
||||
#include "core.h"
|
||||
|
||||
@@ -56,7 +54,7 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
|
||||
|
||||
ViewerDisplayWidget::~ViewerDisplayWidget()
|
||||
{
|
||||
ContextCleanup();
|
||||
OnDestroy();
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::SetMatrixTranslate(const QMatrix4x4 &mat)
|
||||
@@ -104,13 +102,13 @@ void ViewerDisplayWidget::SetImage(FramePtr in_buffer)
|
||||
if (last_loaded_buffer_) {
|
||||
makeCurrent();
|
||||
|
||||
if (!texture_.IsCreated()
|
||||
|| texture_.width() != in_buffer->width()
|
||||
|| texture_.height() != in_buffer->height()
|
||||
|| texture_.format() != in_buffer->format()) {
|
||||
texture_.Create(context(), in_buffer->video_params(), in_buffer->data(), in_buffer->linesize_pixels());
|
||||
if (!texture_
|
||||
|| texture_->width() != in_buffer->width()
|
||||
|| texture_->height() != in_buffer->height()
|
||||
|| texture_->format() != in_buffer->format()) {
|
||||
texture_ = renderer()->CreateTexture(in_buffer->video_params(), in_buffer->data(), in_buffer->linesize_pixels());
|
||||
} else {
|
||||
texture_.Upload(in_buffer);
|
||||
texture_->Upload(in_buffer->data(), in_buffer->linesize_bytes());
|
||||
}
|
||||
|
||||
doneCurrent();
|
||||
@@ -205,7 +203,7 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event)
|
||||
emit DragStarted();
|
||||
}
|
||||
|
||||
QOpenGLWidget::mousePressEvent(event);
|
||||
ManagedDisplayWidget::mousePressEvent(event);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -252,7 +250,7 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
} else {
|
||||
|
||||
// Default behavior
|
||||
QOpenGLWidget::mouseMoveEvent(event);
|
||||
ManagedDisplayWidget::mouseMoveEvent(event);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -275,49 +273,33 @@ void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||
} else {
|
||||
|
||||
// Default behavior
|
||||
QOpenGLWidget::mouseReleaseEvent(event);
|
||||
ManagedDisplayWidget::mouseReleaseEvent(event);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
QMatrix4x4 ViewerDisplayWidget::GetMatrixTranslate()
|
||||
void ViewerDisplayWidget::OnInit()
|
||||
{
|
||||
return translate_matrix_;
|
||||
ManagedDisplayWidget::OnInit();
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::initializeGL()
|
||||
void ViewerDisplayWidget::OnPaint()
|
||||
{
|
||||
ManagedDisplayWidget::initializeGL();
|
||||
|
||||
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ViewerDisplayWidget::ContextCleanup, Qt::DirectConnection);
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::paintGL()
|
||||
{
|
||||
// Get functions attached to this context (they will already be initialized)
|
||||
QOpenGLFunctions* f = context()->functions();
|
||||
|
||||
// Clear background to empty
|
||||
f->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
f->glClear(GL_COLOR_BUFFER_BIT);
|
||||
renderer()->ClearDestination();
|
||||
|
||||
// We only draw if we have a pipeline
|
||||
if (last_loaded_buffer_ && color_service()) {
|
||||
|
||||
if (deinterlace_) {
|
||||
qDebug() << "FIXME: Deinterlacing is currently broken, we're working on this...";
|
||||
//color_service()->pipeline()->setUniformValue("ove_resolution", texture_.width(), texture_.height());
|
||||
//color_service()->pipeline()->setUniformValue("ove_deinterlace", deinterlace_);
|
||||
}
|
||||
|
||||
// Bind retrieved texture
|
||||
f->glBindTexture(GL_TEXTURE_2D, texture_.texture());
|
||||
|
||||
// Set some parameters
|
||||
color_service()->pipeline()->bind();
|
||||
color_service()->pipeline()->setUniformValue("ove_resolution", texture_.width(), texture_.height());
|
||||
color_service()->pipeline()->setUniformValue("ove_deinterlace", deinterlace_);
|
||||
color_service()->pipeline()->release();
|
||||
|
||||
// Blit using the color service
|
||||
color_service()->ProcessOpenGL(true, GetCompleteMatrixFlippedYTranslation());
|
||||
|
||||
// Release retrieved texture
|
||||
f->glBindTexture(GL_TEXTURE_2D, 0);
|
||||
renderer()->SetViewport(width(), height());
|
||||
renderer()->BlitColorManaged(color_service(), texture_.get());
|
||||
|
||||
}
|
||||
|
||||
@@ -371,6 +353,18 @@ void ViewerDisplayWidget::paintGL()
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::OnDestroy()
|
||||
{
|
||||
ManagedDisplayWidget::OnDestroy();
|
||||
|
||||
texture_ = nullptr;
|
||||
}
|
||||
|
||||
QMatrix4x4 ViewerDisplayWidget::GetMatrixTranslate()
|
||||
{
|
||||
return translate_matrix_;
|
||||
}
|
||||
|
||||
QPointF ViewerDisplayWidget::GetTexturePosition(const QPoint &screen_pos)
|
||||
{
|
||||
return GetTexturePosition(screen_pos.x(), screen_pos.y());
|
||||
@@ -426,13 +420,4 @@ QTransform ViewerDisplayWidget::GenerateWorldTransform()
|
||||
return world;
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::ContextCleanup()
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
texture_.Destroy();
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -178,19 +178,22 @@ protected:
|
||||
*/
|
||||
virtual void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Initialize function to set up the OpenGL context upon its construction
|
||||
*
|
||||
* Currently primarily used to regenerate the pipeline shader used for drawing.
|
||||
*/
|
||||
virtual void initializeGL() override;
|
||||
virtual void OnInit() override;
|
||||
|
||||
/**
|
||||
* @brief Paint function to display the texture (received in SetTexture()) on screen.
|
||||
*
|
||||
* Simple OpenGL drawing function for painting the texture on screen. Standardized around OpenGL ES 3.2 Core.
|
||||
*/
|
||||
virtual void paintGL() override;
|
||||
virtual void OnPaint() override;
|
||||
|
||||
virtual void OnDestroy() override;
|
||||
|
||||
private:
|
||||
QPointF GetTexturePosition(const QPoint& screen_pos);
|
||||
@@ -208,7 +211,7 @@ private:
|
||||
/**
|
||||
* @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL().
|
||||
*/
|
||||
QVariant texture_;
|
||||
Renderer::TexturePtr texture_;
|
||||
|
||||
/**
|
||||
* @brief Translation only matrix (defaults to identity).
|
||||
@@ -247,12 +250,6 @@ private:
|
||||
|
||||
bool deinterlace_;
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Slot to connect just before the OpenGL context is destroyed to clean up resources
|
||||
*/
|
||||
void ContextCleanup();
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
Reference in New Issue
Block a user