Merge branch 'master' into pr/1987

This commit is contained in:
itsmattkc
2022-07-27 10:05:00 -07:00
45 changed files with 546 additions and 340 deletions
+39 -68
View File
@@ -78,9 +78,9 @@ private:
#define PRINT_GL_ERRORS ErrorPrinter __e(__FUNCTION__, functions_)
#define GL_PREAMBLE \
QMutexLocker __l(&global_opengl_mutex);
//QMutexLocker __l(&global_opengl_mutex);
QMutex global_opengl_mutex;
//QMutex global_opengl_mutex;
OpenGLRenderer::OpenGLRenderer(QObject* parent) :
Renderer(parent),
@@ -107,7 +107,7 @@ void OpenGLRenderer::Init(QOpenGLContext *existing_ctx)
bool OpenGLRenderer::Init()
{
QMutexLocker locker(&global_opengl_mutex);
GL_PREAMBLE;
if (context_) {
qCritical() << "Can't initialize already initialized OpenGLRenderer";
@@ -177,7 +177,7 @@ void OpenGLRenderer::ClearDestination(Texture *texture, double r, double g, doub
GL_PREAMBLE;
if (texture) {
AttachTextureAsDestination(texture);
AttachTextureAsDestination(texture->id());
}
ClearDestinationInternal(r, g, b, a);
@@ -187,16 +187,11 @@ void OpenGLRenderer::ClearDestination(Texture *texture, double r, double g, doub
}
}
QVariant OpenGLRenderer::CreateNativeTexture2D(int width, int height, VideoParams::Format format, int channel_count, const void *data, int linesize)
QVariant OpenGLRenderer::CreateNativeTexture(int width, int height, int depth, VideoParams::Format format, int channel_count, const void *data, int linesize)
{
GL_PREAMBLE;
return CreateNativeTexture2DInternal(width, height, format, channel_count, data, linesize);
}
QVariant OpenGLRenderer::CreateNativeTexture3D(int width, int height, int depth, VideoParams::Format format, int channel_count, const void *data, int linesize)
{
GL_PREAMBLE;
bool is_3d = depth > 1;
// Generate new texture
GLuint texture;
@@ -205,23 +200,32 @@ QVariant OpenGLRenderer::CreateNativeTexture3D(int width, int height, int depth,
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
GLenum target_current = is_3d ? GL_TEXTURE_BINDING_3D : GL_TEXTURE_BINDING_2D;
GLenum target = is_3d ? GL_TEXTURE_3D : GL_TEXTURE_2D;
GLint current_tex;
functions_->glGetIntegerv(GL_TEXTURE_BINDING_3D, &current_tex);
functions_->glGetIntegerv(target_current, &current_tex);
functions_->glBindTexture(GL_TEXTURE_3D, texture);
functions_->glBindTexture(target, texture);
context_->extraFunctions()->glTexImage3D(GL_TEXTURE_3D, 0, GetInternalFormat(format, channel_count),
width, height, depth, 0, GetPixelFormat(channel_count),
GetPixelType(format), data);
if (is_3d) {
context_->extraFunctions()->glTexImage3D(target, 0, GetInternalFormat(format, channel_count),
width, height, depth, 0, GetPixelFormat(channel_count),
GetPixelType(format), data);
} else {
functions_->glTexImage2D(target, 0, GetInternalFormat(format, channel_count),
width, height, 0, GetPixelFormat(channel_count),
GetPixelType(format), data);
}
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
functions_->glBindTexture(GL_TEXTURE_3D, current_tex);
functions_->glBindTexture(target, current_tex);
return texture;
}
void OpenGLRenderer::AttachTextureAsDestination(Texture* texture)
void OpenGLRenderer::AttachTextureAsDestination(const QVariant &texture)
{
PRINT_GL_ERRORS;
@@ -229,7 +233,7 @@ void OpenGLRenderer::AttachTextureAsDestination(Texture* texture)
functions_->glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
texture->id().value<GLuint>(),
texture.value<GLuint>(),
0);
}
@@ -287,15 +291,16 @@ void OpenGLRenderer::DestroyNativeShader(QVariant shader)
functions_->glDeleteProgram(program);
}
void OpenGLRenderer::UploadToTexture(Texture *texture, const void *data, int linesize)
void OpenGLRenderer::UploadToTexture(const QVariant &handle, const VideoParams &p, const void *data, int linesize)
{
GL_PREAMBLE;
GLuint t = texture->id().value<GLuint>();
const VideoParams& p = texture->params();
GLuint t = handle.value<GLuint>();
GLenum tex_type = texture->type() == Texture::k2D ? GL_TEXTURE_2D : GL_TEXTURE_3D;
GLenum tex_binding = texture->type() == Texture::k2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_3D;
bool is_3d = p.is_3d();
GLenum tex_type = !is_3d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
GLenum tex_binding = !is_3d ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_3D;
// Store currently bound texture so it can be restored later
GLint current_tex;
@@ -308,7 +313,7 @@ void OpenGLRenderer::UploadToTexture(Texture *texture, const void *data, int lin
{
PRINT_GL_ERRORS;
if (texture->type() == Texture::k2D) {
if (!is_3d) {
functions_->glTexSubImage2D(tex_type, 0, 0, 0,
p.effective_width(), p.effective_height(),
GetPixelFormat(p.channel_count()), GetPixelType(p.format()),
@@ -326,16 +331,14 @@ void OpenGLRenderer::UploadToTexture(Texture *texture, const void *data, int lin
functions_->glBindTexture(tex_type, current_tex);
}
void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int linesize)
void OpenGLRenderer::DownloadFromTexture(const QVariant &id, const VideoParams &p, void *data, int linesize)
{
GL_PREAMBLE;
const VideoParams& p = texture->params();
GLint current_tex;
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_tex);
AttachTextureAsDestination(texture);
AttachTextureAsDestination(id);
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, linesize);
@@ -366,7 +369,7 @@ void OpenGLRenderer::Flush()
Color OpenGLRenderer::GetPixelFromTexture(Texture *texture, const QPointF &pt)
{
AttachTextureAsDestination(texture);
AttachTextureAsDestination(texture->id());
QByteArray data(VideoParams::GetBytesPerPixel(texture->format(), texture->channel_count()), Qt::Uninitialized);
@@ -502,7 +505,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
functions_->glActiveTexture(GL_TEXTURE0 + i);
GLenum target = (texture && texture->type() == Texture::k3D) ? GL_TEXTURE_3D : GL_TEXTURE_2D;
GLenum target = (texture && texture->params().is_3d()) ? GL_TEXTURE_3D : GL_TEXTURE_2D;
functions_->glBindTexture(target, tex_id);
if (tex_id) {
@@ -584,11 +587,11 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
TexturePtr output_tex, input_tex;
if (real_iteration_count > 1) {
// Create one texture to bounce off
output_tex = CreateTextureFromNativeHandle(CreateNativeTexture2DInternal(destination_params), destination_params);
output_tex = CreateTexture(destination_params);
if (real_iteration_count > 2) {
// Create a second texture bounce off
input_tex = CreateTextureFromNativeHandle(CreateNativeTexture2DInternal(destination_params), destination_params);
input_tex = CreateTexture(destination_params);
}
}
@@ -604,7 +607,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
// This is the last iteration, draw to the destination
if (destination) {
// If we have a destination texture, draw to it
AttachTextureAsDestination(destination);
AttachTextureAsDestination(destination->id());
} else if (iteration > 0) {
// Otherwise, if we were iterating before, detach texture now
DetachTextureAsDestination();
@@ -616,7 +619,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
}
} else {
// Always draw to output_tex, which gets swapped with input_tex every iteration
AttachTextureAsDestination(output_tex.get());
AttachTextureAsDestination(output_tex->id());
}
if (iteration > 0) {
@@ -648,7 +651,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
// Release any textures we bound before
for (int i=textures_to_bind.size()-1; i>=0; i--) {
TexturePtr texture = textures_to_bind.at(i).texture;
GLenum target = (texture && texture->type() == Texture::k3D) ? GL_TEXTURE_3D : GL_TEXTURE_2D;
GLenum target = (texture && texture->params().is_3d()) ? GL_TEXTURE_3D : GL_TEXTURE_2D;
functions_->glActiveTexture(GL_TEXTURE0 + i);
functions_->glBindTexture(target, 0);
}
@@ -788,38 +791,6 @@ void OpenGLRenderer::ClearDestinationInternal(double r, double g, double b, doub
functions_->glClear(GL_COLOR_BUFFER_BIT);
}
QVariant OpenGLRenderer::CreateNativeTexture2DInternal(int width, int height, VideoParams::Format format, int channel_count, const void *data, int linesize)
{
GLuint texture;
functions_->glGenTextures(1, &texture);
texture_params_.insert(texture, {width, height, 1, format, channel_count});
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
GLint current_tex;
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_tex);
functions_->glBindTexture(GL_TEXTURE_2D, texture);
{
PRINT_GL_ERRORS;
functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(format, channel_count),
width, height, 0, GetPixelFormat(channel_count),
GetPixelType(format), data);
}
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
return texture;
}
QVariant OpenGLRenderer::CreateNativeTexture2DInternal(const VideoParams &params, const void *data, int linesize)
{
return CreateNativeTexture2DInternal(params.effective_width(), params.effective_height(), params.format(), params.channel_count(), data, linesize);
}
GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code)
{
static const QString shader_preamble =
+10 -15
View File
@@ -47,37 +47,35 @@ public:
virtual void PostDestroy() override;
public slots:
virtual void PostInit() override;
virtual void DestroyInternal() override;
virtual void ClearDestination(olive::Texture *texture = nullptr, double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
virtual QVariant CreateNativeTexture2D(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override;
virtual QVariant CreateNativeTexture3D(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override;
virtual void DestroyNativeTexture(QVariant texture) override;
virtual QVariant CreateNativeShader(olive::ShaderCode code) override;
virtual void DestroyNativeShader(QVariant shader) override;
virtual void UploadToTexture(olive::Texture* texture, const void* data, int linesize) override;
virtual void UploadToTexture(const QVariant &handle, const VideoParams &params, const void* data, int linesize) override;
virtual void DownloadFromTexture(olive::Texture* texture, void* data, int linesize) override;
virtual void DownloadFromTexture(const QVariant &handle, const VideoParams &params, void* data, int linesize) override;
virtual void Flush() override;
virtual Color GetPixelFromTexture(olive::Texture *texture, const QPointF &pt) override;
protected slots:
protected:
virtual void Blit(QVariant shader,
olive::ShaderJob job,
olive::Texture* destination,
olive::VideoParams destination_params,
bool clear_destination) override;
virtual QVariant CreateNativeTexture(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override;
virtual void DestroyNativeTexture(QVariant texture) override;
virtual void DestroyInternal() override;
private:
static GLint GetInternalFormat(VideoParams::Format format, int channel_layout);
@@ -85,7 +83,7 @@ private:
static GLenum GetPixelFormat(int channel_count);
void AttachTextureAsDestination(olive::Texture* texture);
void AttachTextureAsDestination(const QVariant &texture);
void DetachTextureAsDestination();
@@ -93,9 +91,6 @@ private:
void ClearDestinationInternal(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0);
QVariant CreateNativeTexture2DInternal(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0);
QVariant CreateNativeTexture2DInternal(const VideoParams &params, const void* data = nullptr, int linesize = 0);
GLuint CompileShader(GLenum type, const QString &code);
QOpenGLContext* context_;
+8 -5
View File
@@ -61,7 +61,7 @@ PreviewAutoCacher::~PreviewAutoCacher()
SetViewerNode(nullptr);
}
RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t)
RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t, bool dry)
{
// If we have a single frame render queued (but not yet sent to the RenderManager), cancel it now
CancelQueuedSingleFrameRender();
@@ -70,6 +70,7 @@ RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t)
auto sfr = std::make_shared<RenderTicket>();
sfr->Start();
sfr->setProperty("time", QVariant::fromValue(t));
sfr->setProperty("dry", dry);
// Queue it and try to render
single_frame_render_ = sfr;
@@ -566,7 +567,8 @@ void PreviewAutoCacher::TryRender()
if (single_frame_render_) {
// Check if already caching this
RenderTicketWatcher *watcher = RenderFrame(single_frame_render_->property("time").value<rational>(),
nullptr);
nullptr,
single_frame_render_->property("dry").toBool());
video_immediate_passthroughs_[watcher].append(single_frame_render_);
single_frame_render_ = nullptr;
@@ -583,7 +585,7 @@ void PreviewAutoCacher::TryRender()
// We want this hash, if we're not already rendering, start render now
if (!render_task) {
// Don't render any hash more than once
RenderFrame(t, viewer_node_->video_frame_cache());
RenderFrame(t, viewer_node_->video_frame_cache(), false);
}
emit SignalCacheProxyTaskProgress(double(queued_frame_iterator_.frame_index()) / double(queued_frame_iterator_.size()));
@@ -609,7 +611,7 @@ void PreviewAutoCacher::TryRender()
}
}
RenderTicketWatcher* PreviewAutoCacher::RenderFrame(Node *node, const rational& time, FrameHashCache *cache)
RenderTicketWatcher* PreviewAutoCacher::RenderFrame(Node *node, const rational& time, FrameHashCache *cache, bool dry)
{
RenderTicketWatcher* watcher = new RenderTicketWatcher();
watcher->setProperty("job", QVariant::fromValue(last_update_time_));
@@ -623,7 +625,8 @@ RenderTicketWatcher* PreviewAutoCacher::RenderFrame(Node *node, const rational&
time,
RenderMode::kOffline,
cache,
RenderManager::kTexture));
dry ? RenderManager::kNull : RenderManager::kTexture));
return watcher;
}
+4 -4
View File
@@ -49,7 +49,7 @@ public:
virtual ~PreviewAutoCacher() override;
RenderTicketPtr GetSingleFrame(const rational& t);
RenderTicketPtr GetSingleFrame(const rational& t, bool dry = false);
RenderTicketPtr GetRangeOfAudio(TimeRange range);
@@ -98,10 +98,10 @@ signals:
private:
void TryRender();
RenderTicketWatcher *RenderFrame(Node *node, const rational &time, FrameHashCache *cache);
RenderTicketWatcher *RenderFrame(const rational &time, FrameHashCache *cache)
RenderTicketWatcher *RenderFrame(Node *node, const rational &time, FrameHashCache *cache, bool dry);
RenderTicketWatcher *RenderFrame(const rational &time, FrameHashCache *cache, bool dry)
{
return RenderFrame(copied_viewer_node_->GetConnectedTextureOutput(), time, cache);
return RenderFrame(copied_viewer_node_->GetConnectedTextureOutput(), time, cache, dry);
}
RenderTicketPtr RenderAudio(Node *node, const TimeRange &range, bool generate_waveforms);
+66 -26
View File
@@ -20,36 +20,62 @@
#include "renderer.h"
#include <QDateTime>
#include <QTimer>
#include <QVector2D>
#include "common/ocioutils.h"
namespace olive {
Renderer::Renderer(QObject *parent) :
QObject(parent)
{
}
TexturePtr Renderer::CreateTexture(const VideoParams &params, Texture::Type type, const void *data, int linesize)
{
QVariant v;
if (type == Texture::k3D) {
v = CreateNativeTexture3D(params.effective_width(), params.effective_height(),
params.effective_depth(), params.format(), params.channel_count(), data, linesize);
} else {
v = CreateNativeTexture2D(params.effective_width(), params.effective_height(), params.format(),
params.channel_count(), data, linesize);
}
return CreateTextureFromNativeHandle(v, params, type);
}
TexturePtr Renderer::CreateTexture(const VideoParams &params, const void *data, int linesize)
{
return CreateTexture(params, Texture::k2D, data, linesize);
QVariant v;
if (USE_TEXTURE_CACHE) {
for (auto it=texture_cache_.begin(); it!=texture_cache_.end(); it++) {
if (it->width == params.effective_width()
&& it->height == params.effective_height()
&& it->depth == params.effective_depth()
&& it->format == params.format()
&& it->channel_count == params.channel_count()) {
v = it->handle;
texture_cache_.erase(it);
break;
}
}
}
if (v.isNull()) {
v = CreateNativeTexture(params.effective_width(), params.effective_height(), params.effective_depth(),
params.format(), params.channel_count(), data, linesize);
} else if (data) {
UploadToTexture(v, params, data, linesize);
} else {
this->Flush();
}
return CreateTextureFromNativeHandle(v, params);
}
void Renderer::DestroyTexture(Texture *texture)
{
if (USE_TEXTURE_CACHE) {
texture_cache_.push_back({texture->params().effective_width(),
texture->params().effective_height(),
texture->params().effective_depth(),
texture->params().format(),
texture->params().channel_count(),
texture->id(),
QDateTime::currentMSecsSinceEpoch()});
ClearOldTextures();
} else {
DestroyNativeTexture(texture->id());
}
}
TexturePtr Renderer::InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams &params)
@@ -95,16 +121,21 @@ void Renderer::Destroy()
interlace_texture_.clear();
}
for (auto it=texture_cache_.begin(); it!=texture_cache_.end(); it++) {
DestroyNativeTexture(it->handle);
}
texture_cache_.clear();
DestroyInternal();
}
TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, const VideoParams &params, Texture::Type type)
TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, const VideoParams &params)
{
if (v.isNull()) {
return nullptr;
}
return std::make_shared<Texture>(this, v, params, type);
return std::make_shared<Texture>(this, v, params);
}
bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::ColorContext *ctx)
@@ -175,8 +206,7 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::Col
}
// Allocate 3D LUT
color_ctx.lut3d_textures[i].texture = CreateTexture(VideoParams(edge_len, edge_len, edge_len, VideoParams::kFormatFloat32, VideoParams::kRGBChannelCount),
Texture::k3D, values);
color_ctx.lut3d_textures[i].texture = CreateTexture(VideoParams(edge_len, edge_len, edge_len, VideoParams::kFormatFloat32, VideoParams::kRGBChannelCount), values);
color_ctx.lut3d_textures[i].name = sampler_name;
color_ctx.lut3d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear;
}
@@ -206,9 +236,7 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::Col
}
// Allocate 1D LUT
color_ctx.lut1d_textures[i].texture = CreateTexture(VideoParams(width, height, VideoParams::kFormatFloat32, (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? 1 : VideoParams::kRGBChannelCount),
Texture::k2D,
values);
color_ctx.lut1d_textures[i].texture = CreateTexture(VideoParams(width, height, VideoParams::kFormatFloat32, (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? 1 : VideoParams::kRGBChannelCount), values);
color_ctx.lut1d_textures[i].name = sampler_name;
color_ctx.lut1d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear;
}
@@ -219,6 +247,18 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::Col
}
}
void Renderer::ClearOldTextures()
{
for (auto it=texture_cache_.begin(); it!=texture_cache_.end(); ) {
if (it->accessed < QDateTime::currentMSecsSinceEpoch() - MAX_TEXTURE_LIFE) {
DestroyNativeTexture(it->handle);
it = texture_cache_.erase(it);
} else {
it++;
}
}
}
void Renderer::BlitColorManaged(const ColorTransformJob &color_job, Texture *destination, const VideoParams &params)
{
ColorContext color_ctx;
+29 -14
View File
@@ -45,9 +45,10 @@ public:
virtual bool Init() = 0;
TexturePtr CreateTexture(const VideoParams& params, Texture::Type type, const void* data = nullptr, int linesize = 0);
TexturePtr CreateTexture(const VideoParams& params, const void *data = nullptr, int linesize = 0);
void DestroyTexture(Texture *texture);
void BlitToTexture(QVariant shader,
olive::ShaderJob job,
olive::Texture* destination,
@@ -82,39 +83,34 @@ public:
virtual void PostDestroy() = 0;
public slots:
virtual void PostInit() = 0;
virtual void DestroyInternal() = 0;
virtual void ClearDestination(olive::Texture *texture = nullptr, double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) = 0;
virtual QVariant CreateNativeTexture2D(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) = 0;
virtual QVariant CreateNativeTexture3D(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) = 0;
virtual void DestroyNativeTexture(QVariant texture) = 0;
virtual QVariant CreateNativeShader(olive::ShaderCode code) = 0;
virtual void DestroyNativeShader(QVariant shader) = 0;
virtual void UploadToTexture(olive::Texture* texture, const void* data, int linesize) = 0;
virtual void UploadToTexture(const QVariant &handle, const VideoParams &params, const void* data, int linesize) = 0;
virtual void DownloadFromTexture(olive::Texture* texture, void* data, int linesize) = 0;
virtual void DownloadFromTexture(const QVariant &handle, const VideoParams &params, void* data, int linesize) = 0;
virtual void Flush() = 0;
virtual Color GetPixelFromTexture(olive::Texture *texture, const QPointF &pt) = 0;
protected slots:
protected:
virtual void Blit(QVariant shader,
olive::ShaderJob job,
olive::Texture* destination,
olive::VideoParams destination_params,
bool clear_destination) = 0;
protected:
TexturePtr CreateTextureFromNativeHandle(const QVariant &v, const VideoParams &params, Texture::Type type = Texture::k2D);
virtual QVariant CreateNativeTexture(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) = 0;
virtual void DestroyNativeTexture(QVariant texture) = 0;
virtual void DestroyInternal() = 0;
private:
struct ColorContext {
@@ -130,10 +126,29 @@ private:
};
TexturePtr CreateTextureFromNativeHandle(const QVariant &v, const VideoParams &params);
bool GetColorContext(const ColorTransformJob &color_job, ColorContext* ctx);
void ClearOldTextures();
QHash<QString, ColorContext> color_cache_;
struct CachedTexture
{
int width;
int height;
int depth;
VideoParams::Format format;
int channel_count;
QVariant handle;
qint64 accessed;
};
static const int MAX_TEXTURE_LIFE = 5000;
static const bool USE_TEXTURE_CACHE = true;
std::list<CachedTexture> texture_cache_;
QMutex color_cache_mutex_;
QVariant default_shader_;
+13 -1
View File
@@ -35,6 +35,7 @@
namespace olive {
RenderManager* RenderManager::instance_ = nullptr;
const rational RenderManager::kDryRunInterval = rational(10);
RenderManager::RenderManager(QObject *parent) :
backend_(kOpenGL),
@@ -52,9 +53,11 @@ RenderManager::RenderManager(QObject *parent) :
if (context_) {
video_thread_ = new RenderThread(context_, decoder_cache_, shader_cache_, this);
dry_run_thread_ = new RenderThread(nullptr, decoder_cache_, shader_cache_, this);
audio_thread_ = new RenderThread(nullptr, decoder_cache_, shader_cache_, this);
video_thread_->start(QThread::IdlePriority);
dry_run_thread_->start(QThread::IdlePriority);
audio_thread_->start(QThread::IdlePriority);
}
@@ -73,6 +76,9 @@ RenderManager::~RenderManager()
video_thread_->quit();
video_thread_->wait();
dry_run_thread_->quit();
dry_run_thread_->wait();
context_->PostDestroy();
delete context_;
@@ -129,7 +135,11 @@ RenderTicketPtr RenderManager::RenderFrame(Node *node, ColorManager* color_manag
ticket->setProperty("cacheuuid", QVariant::fromValue(cache->GetUuid()));
}
video_thread_->AddTicket(ticket);
if (return_type == ReturnType::kNull) {
dry_run_thread_->AddTicket(ticket);
} else {
video_thread_->AddTicket(ticket);
}
return ticket;
}
@@ -157,6 +167,8 @@ bool RenderManager::RemoveTicket(RenderTicketPtr ticket)
return true;
} else if (audio_thread_->RemoveTicket(ticket)) {
return true;
} else if (dry_run_thread_->RemoveTicket(ticket)) {
return true;
} else {
return false;
}
+5 -1
View File
@@ -97,9 +97,12 @@ public:
enum ReturnType {
kTexture,
kFrame
kFrame,
kNull
};
static const rational kDryRunInterval;
/**
* @brief Asynchronously generate a frame at a given time
*
@@ -168,6 +171,7 @@ private:
QTimer *decoder_clear_timer_;
RenderThread *video_thread_;
RenderThread *dry_run_thread_;
RenderThread *audio_thread_;
private slots:
+58 -51
View File
@@ -123,7 +123,7 @@ FramePtr RenderProcessor::GenerateFrame(TexturePtr texture, const rational& time
render_ctx_->Flush();
render_ctx_->DownloadFromTexture(texture.get(), frame->data(), frame->linesize_pixels());
render_ctx_->DownloadFromTexture(texture->id(), texture->params(), frame->data(), frame->linesize_pixels());
}
return frame;
@@ -151,53 +151,57 @@ void RenderProcessor::Run()
TexturePtr texture = GenerateTexture(time, frame_length);
if (GetCacheVideoParams().interlacing() != VideoParams::kInterlaceNone) {
// Get next between frame and interlace it
TexturePtr top = texture;
TexturePtr bottom = GenerateTexture(time + frame_length, frame_length);
if (GetCacheVideoParams().interlacing() == VideoParams::kInterlacedBottomFirst) {
std::swap(top, bottom);
}
texture = render_ctx_->InterlaceTexture(top, bottom, GetCacheVideoParams());
}
if (HeardCancel()) {
// Finish cancelled ticket with nothing since we can't guarantee the frame we generated
// is actually "complete
if (!render_ctx_) {
ticket_->Finish();
} else {
RenderManager::ReturnType return_type = RenderManager::ReturnType(ticket_->property("return").toInt());
if (GetCacheVideoParams().interlacing() != VideoParams::kInterlaceNone) {
// Get next between frame and interlace it
TexturePtr top = texture;
TexturePtr bottom = GenerateTexture(time + frame_length, frame_length);
FramePtr frame;
QString cache = ticket_->property("cache").toString();
if (return_type == RenderManager::kFrame || !cache.isEmpty()) {
// Convert to CPU frame
frame = GenerateFrame(texture, time);
// Save to cache if requested
if (!cache.isEmpty()) {
rational timebase = ticket_->property("cachetimebase").value<rational>();
QUuid uuid = ticket_->property("cacheuuid").value<QUuid>();
bool cache_result = FrameHashCache::SaveCacheFrame(cache, uuid, time, timebase, frame);
ticket_->setProperty("cached", cache_result);
if (GetCacheVideoParams().interlacing() == VideoParams::kInterlacedBottomFirst) {
std::swap(top, bottom);
}
texture = render_ctx_->InterlaceTexture(top, bottom, GetCacheVideoParams());
}
if (return_type == RenderManager::kTexture) {
// Return GPU texture
if (!texture) {
texture = render_ctx_->CreateTexture(GetCacheVideoParams());
render_ctx_->ClearDestination(texture.get());
if (HeardCancel()) {
// Finish cancelled ticket with nothing since we can't guarantee the frame we generated
// is actually "complete
ticket_->Finish();
} else {
RenderManager::ReturnType return_type = RenderManager::ReturnType(ticket_->property("return").toInt());
FramePtr frame;
QString cache = ticket_->property("cache").toString();
if (return_type == RenderManager::kFrame || !cache.isEmpty()) {
// Convert to CPU frame
frame = GenerateFrame(texture, time);
// Save to cache if requested
if (!cache.isEmpty()) {
rational timebase = ticket_->property("cachetimebase").value<rational>();
QUuid uuid = ticket_->property("cacheuuid").value<QUuid>();
bool cache_result = FrameHashCache::SaveCacheFrame(cache, uuid, time, timebase, frame);
ticket_->setProperty("cached", cache_result);
}
}
render_ctx_->Flush();
if (return_type == RenderManager::kTexture) {
// Return GPU texture
if (!texture) {
texture = render_ctx_->CreateTexture(GetCacheVideoParams());
render_ctx_->ClearDestination(texture.get());
}
ticket_->Finish(QVariant::fromValue(texture));
} else {
ticket_->Finish(QVariant::fromValue(frame));
render_ctx_->Flush();
ticket_->Finish(QVariant::fromValue(texture));
} else {
ticket_->Finish(QVariant::fromValue(frame));
}
}
}
break;
@@ -265,6 +269,11 @@ DecoderPtr RenderProcessor::ResolveDecoderFromInput(const QString& decoder_id, c
<< "::" << stream.stream();
return nullptr;
}
if (!render_ctx_) {
// Assume dry run and increment access time
decoder.decoder->IncrementAccessTime(RenderManager::kDryRunInterval.toDouble() * 1000);
}
}
return decoder.decoder;
@@ -404,10 +413,6 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time)
{
if (!render_ctx_) {
return;
}
if (ticket_->property("type").value<RenderManager::TicketType>() != RenderManager::kTypeVideo) {
// Video cannot contribute to audio, so we do nothing here
return;
@@ -440,21 +445,23 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ
break;
case VideoParams::kVideoTypeImageSequence:
{
// Since image sequences involve multiple files, we don't engage the decoder cache
decoder = Decoder::CreateFromID(decoder_id);
if (render_ctx_) {
// Since image sequences involve multiple files, we don't engage the decoder cache
decoder = Decoder::CreateFromID(decoder_id);
QString frame_filename;
QString frame_filename;
int64_t frame_number = stream_data.get_time_in_timebase_units(input_time);
frame_filename = Decoder::TransformImageSequenceFileName(stream.filename(), frame_number);
int64_t frame_number = stream_data.get_time_in_timebase_units(input_time);
frame_filename = Decoder::TransformImageSequenceFileName(stream.filename(), frame_number);
// Decoder will close automatically since it's a stream_ptr
decoder->Open(Decoder::CodecStream(frame_filename, stream_data.stream_index(), GetCurrentBlock()));
// Decoder will close automatically since it's a stream_ptr
decoder->Open(Decoder::CodecStream(frame_filename, stream_data.stream_index(), GetCurrentBlock()));
}
break;
}
}
if (decoder) {
if (decoder && render_ctx_) {
Decoder::RetrieveVideoParams p;
p.divider = stream.video_params().divider();
p.maximum_format = destination->format();
+3 -3
View File
@@ -29,21 +29,21 @@ const Texture::Interpolation Texture::kDefaultInterpolation = Texture::kMipmappe
Texture::~Texture()
{
if (renderer_) {
renderer_->DestroyNativeTexture(id_);
renderer_->DestroyTexture(this);
}
}
void Texture::Upload(void *data, int linesize)
{
if (renderer_) {
renderer_->UploadToTexture(this, data, linesize);
renderer_->UploadToTexture(this->id(), this->params(), data, linesize);
}
}
void Texture::Download(void *data, int linesize)
{
if (renderer_) {
renderer_->DownloadFromTexture(this, data, linesize);
renderer_->DownloadFromTexture(this->id(), this->params(), data, linesize);
}
}
+3 -17
View File
@@ -32,11 +32,6 @@ class Renderer;
class Texture
{
public:
enum Type {
k2D,
k3D
};
enum Interpolation {
kNearest,
kLinear,
@@ -50,19 +45,17 @@ public:
*/
Texture(const VideoParams& param) :
renderer_(nullptr),
params_(param),
type_(k2D)
params_(param)
{
}
/**
* @brief Construct a real texture linked to a renderer backend
*/
Texture(Renderer* renderer, const QVariant& native, const VideoParams& param, Type type) :
Texture(Renderer* renderer, const QVariant& native, const VideoParams& param) :
renderer_(renderer),
params_(param),
id_(native),
type_(type)
id_(native)
{
}
@@ -117,11 +110,6 @@ public:
return params_.pixel_aspect_ratio();
}
Type type() const
{
return type_;
}
Renderer* renderer() const
{
return renderer_;
@@ -134,8 +122,6 @@ private:
QVariant id_;
Type type_;
};
using TexturePtr = std::shared_ptr<Texture>;
+2
View File
@@ -121,6 +121,8 @@ public:
calculate_effective_size();
}
bool is_3d() const { return depth_ > 1; }
const rational& time_base() const
{
return time_base_;