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:
itsmattkc
2020-11-10 11:24:51 +11:00
parent 52b98f3fa3
commit 1d61f89920
42 changed files with 927 additions and 820 deletions
+134 -71
View File
@@ -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,29 +129,58 @@ void OpenGLRenderer::PostInit()
void OpenGLRenderer::Destroy()
{
// Delete vertex array object
vao_.destroy();
if (context_) {
// Delete buffers
vert_vbo_.destroy();
frag_vbo_.destroy();
// Delete framebuffer
functions_->glDeleteFramebuffers(1, &framebuffer_);
// Delete vertex array object
vao_.destroy();
// Delete all shaders
qDeleteAll(shader_cache_);
shader_cache_.clear();
// Delete framebuffer
functions_->glDeleteFramebuffers(1, &framebuffer_);
// Delete context if it belongs to us
if (context_->parent() == this) {
delete context_;
}
context_ = nullptr;
// Delete all shaders
qDeleteAll(shader_cache_);
shader_cache_.clear();
// Destroy surface if we created it
if (surface_.isValid()) {
surface_.destroy();
// Delete context if it belongs to us
if (context_->parent() == this) {
delete context_;
}
context_ = nullptr;
// Destroy surface if we created it
if (surface_.isValid()) {
surface_.destroy();
}
}
}
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 &params)
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,20 +532,15 @@ 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);
}
// Reset framebuffer to default
DetachTextureAsDestination();
// Release any textures we bound before
for (int i=textures_to_bind.size()-1; i>=0; i--) {
functions_->glActiveTexture(GL_TEXTURE0 + 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;
+20 -11
View File
@@ -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 &params) 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
+39 -14
View File
@@ -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 &params) = 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
+81 -39
View File
@@ -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 &param, 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 &params)
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
+25 -14
View File
@@ -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 &params) 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
+4 -8
View File
@@ -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;
}
-9
View File
@@ -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);
+1 -1
View File
@@ -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());
+12 -1
View File
@@ -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
+7 -20
View File
@@ -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;
}
image_format = PixelFormat::PIX_FMT_RGBA16F;
} else {
if (has_alpha) {
image_format = PixelFormat::PIX_FMT_RGBA32F;
} else {
image_format = PixelFormat::PIX_FMT_RGB32F;
}
image_format = PixelFormat::PIX_FMT_RGBA32F;
}
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.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));
}
framebuffer.insert("A", Imf::Slice(pix_type, data + 3*bpc, xs, ys));
out.setFrameBuffer(framebuffer);
out.writePixels(vparam.effective_height());
+11 -102
View File
@@ -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 {
+1 -19
View File
@@ -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
*/
+36 -18
View File
@@ -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_) {
RenderTicketWatcher* watcher = new RenderTicketWatcher();
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);
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_,
ticket->property("time").value<rational>(),
RenderMode::kOffline, true));
}
single_frame_renders_.clear();
single_frame_render_->Start();
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_,
static_cast<Sequence*>(viewer_node_->parent())->project()->color_manager(),
single_frame_render_->property("time").value<rational>(),
RenderMode::kOffline, true));
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));
}
}
+3 -1
View File
@@ -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
+45 -11
View File
@@ -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);
context_->Init();
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 &params, const rational &time)
@@ -50,9 +76,13 @@ QByteArray RenderManager::Hash(const Node *n, const VideoParams &params, const r
QCryptographicHash hasher(QCryptographicHash::Sha1);
// Embed video parameters into this hash
hasher.addData(reinterpret_cast<const char*>(&params.effective_width()), sizeof(int));
hasher.addData(reinterpret_cast<const char*>(&params.effective_height()), sizeof(int));
hasher.addData(reinterpret_cast<const char*>(&params.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 &params, 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
+16 -2
View File
@@ -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
+77 -76
View File
@@ -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,38 +327,10 @@ 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)) {
SampleBufferPtr frame = decoder->RetrieveAudio(input_time, audio_params, &IsCancelled());
// 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);
if (frame) {
value = QVariant::fromValue(frame);
}
if (frame) {
value = QVariant::fromValue(frame);
}
}
@@ -330,9 +339,11 @@ QVariant RenderProcessor::ProcessAudioFootage(StreamPtr stream, const TimeRange
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);
+8 -9
View File
@@ -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
+45 -6
View File
@@ -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;