From 91c7d8aa4da6b40ec21ebf6962583c06d4c2ab38 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 10 Dec 2019 14:53:47 +1100 Subject: [PATCH] implemented texture cache for performance Creating and destroying textures is a slow process, particularly when we can re-use them throughout most of the render chain. We now keep them stored so they can be re-used which improves performance substantially. --- app/core.cpp | 1 + app/render/backend/opengl/openglbackend.cpp | 7 ++- app/render/backend/opengl/openglbackend.h | 3 ++ app/render/backend/opengl/opengltexture.cpp | 4 +- app/render/backend/opengl/opengltexture.h | 4 +- .../backend/opengl/opengltexturecache.cpp | 8 ++- .../backend/opengl/opengltexturecache.h | 5 +- app/render/backend/opengl/openglworker.cpp | 54 ++++++++++--------- app/render/backend/opengl/openglworker.h | 4 ++ 9 files changed, 55 insertions(+), 35 deletions(-) diff --git a/app/core.cpp b/app/core.cpp index ab47fd8d3..1d45fc085 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -319,6 +319,7 @@ void Core::DeclareTypesForQt() qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); } diff --git a/app/render/backend/opengl/openglbackend.cpp b/app/render/backend/opengl/openglbackend.cpp index 90491a9fa..7754ba3e2 100644 --- a/app/render/backend/opengl/openglbackend.cpp +++ b/app/render/backend/opengl/openglbackend.cpp @@ -32,7 +32,7 @@ bool OpenGLBackend::InitInternal() // Initiate one thread per CPU core for (int i=0;iSetParameters(params()); processors_.append(processor); } @@ -145,9 +145,8 @@ void OpenGLBackend::ThreadCompletedFrame(NodeDependency path, QByteArray hash, N SetWorkerBusyState(static_cast(sender()), false); QVariant value = table.Get(NodeParam::kTexture); - OpenGLTexturePtr texture = value.value(); - if (!texture) { + if (value.isNull()) { // No frame received, we set hash to an empty frame_cache()->RemoveHash(path.in(), hash); } else { @@ -159,7 +158,7 @@ void OpenGLBackend::ThreadCompletedFrame(NodeDependency path, QByteArray hash, N "Download", Q_ARG(NodeDependency, path), Q_ARG(QByteArray, hash), - Q_ARG(QVariant, QVariant::fromValue(texture)), + Q_ARG(QVariant, value), Q_ARG(QString, cache_fn)); last_download_thread_++; diff --git a/app/render/backend/opengl/openglbackend.h b/app/render/backend/opengl/openglbackend.h index e05303d74..7b72a1a24 100644 --- a/app/render/backend/opengl/openglbackend.h +++ b/app/render/backend/opengl/openglbackend.h @@ -5,6 +5,7 @@ #include "openglframebuffer.h" #include "openglworker.h" #include "opengltexture.h" +#include "opengltexturecache.h" #include "openglshader.h" #include "openglshadercache.h" @@ -34,6 +35,8 @@ private: OpenGLShaderCache shader_cache_; + OpenGLTextureCache texture_cache_; + int last_download_thread_; private slots: diff --git a/app/render/backend/opengl/opengltexture.cpp b/app/render/backend/opengl/opengltexture.cpp index 0ee2a7e8b..186b78162 100644 --- a/app/render/backend/opengl/opengltexture.cpp +++ b/app/render/backend/opengl/opengltexture.cpp @@ -44,7 +44,7 @@ bool OpenGLTexture::IsCreated() const return (texture_ != 0); } -void OpenGLTexture::Create(QOpenGLContext *ctx, int width, int height, const olive::PixelFormat &format, void* data) +void OpenGLTexture::Create(QOpenGLContext *ctx, int width, int height, const olive::PixelFormat &format, const void* data) { if (ctx == nullptr) { qWarning() << "RenderTexture::Create was passed an invalid context"; @@ -182,7 +182,7 @@ uchar *OpenGLTexture::Download() const return data; } -void OpenGLTexture::CreateInternal(GLuint* tex, void *data) +void OpenGLTexture::CreateInternal(GLuint* tex, const void *data) { QOpenGLFunctions* f = context_->functions(); diff --git a/app/render/backend/opengl/opengltexture.h b/app/render/backend/opengl/opengltexture.h index 258bce32d..e84dbecf2 100644 --- a/app/render/backend/opengl/opengltexture.h +++ b/app/render/backend/opengl/opengltexture.h @@ -40,7 +40,7 @@ public: DISABLE_COPY_MOVE(OpenGLTexture) - void Create(QOpenGLContext* ctx, int width, int height, const olive::PixelFormat &format, void *data = nullptr); + void Create(QOpenGLContext* ctx, int width, int height, const olive::PixelFormat &format, const void *data = nullptr); void Create(QOpenGLContext* ctx, FramePtr frame); bool IsCreated() const; @@ -67,7 +67,7 @@ public slots: void Destroy(); private: - void CreateInternal(GLuint *tex, void *data = nullptr); + void CreateInternal(GLuint *tex, const void *data = nullptr); QOpenGLContext* context_; diff --git a/app/render/backend/opengl/opengltexturecache.cpp b/app/render/backend/opengl/opengltexturecache.cpp index a3b1d4600..d3e1e8ab5 100644 --- a/app/render/backend/opengl/opengltexturecache.cpp +++ b/app/render/backend/opengl/opengltexturecache.cpp @@ -7,7 +7,7 @@ OpenGLTextureCache::~OpenGLTextureCache() } } -OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(const VideoRenderingParams ¶ms) +OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(const VideoRenderingParams ¶ms, const void *data) { OpenGLTexturePtr texture = nullptr; @@ -28,10 +28,14 @@ OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(const VideoRenderingPar lock_.unlock(); + QOpenGLContext* ctx = QOpenGLContext::currentContext(); + // If we didn't find a texture, we'll need to create one if (!texture) { texture = std::make_shared(); - texture->Create(QOpenGLContext::currentContext(), params.effective_width(), params.effective_height(), params.format()); + texture->Create(ctx, params.effective_width(), params.effective_height(), params.format(), data); + } else if (data) { + texture->Upload(data); } return std::make_shared(this, texture); diff --git a/app/render/backend/opengl/opengltexturecache.h b/app/render/backend/opengl/opengltexturecache.h index 78092b076..126d648e7 100644 --- a/app/render/backend/opengl/opengltexturecache.h +++ b/app/render/backend/opengl/opengltexturecache.h @@ -3,6 +3,7 @@ #include +#include "openglframebuffer.h" #include "opengltexture.h" #include "render/videoparams.h" @@ -34,7 +35,7 @@ public: DISABLE_COPY_MOVE(OpenGLTextureCache) - ReferencePtr Get(const VideoRenderingParams& params); + ReferencePtr Get(const VideoRenderingParams& params, const void *data = nullptr); private: void Relinquish(Reference* ref); @@ -47,4 +48,6 @@ private: }; +Q_DECLARE_METATYPE(OpenGLTextureCache::ReferencePtr) + #endif // OPENGLTEXTURECACHE_H diff --git a/app/render/backend/opengl/openglworker.cpp b/app/render/backend/opengl/openglworker.cpp index f468baedc..f6dcdfc69 100644 --- a/app/render/backend/opengl/openglworker.cpp +++ b/app/render/backend/opengl/openglworker.cpp @@ -7,12 +7,13 @@ #include "render/colormanager.h" #include "render/pixelservice.h" -OpenGLWorker::OpenGLWorker(QOpenGLContext *share_ctx, OpenGLShaderCache *shader_cache, VideoRenderFrameCache *frame_cache, QObject *parent) : +OpenGLWorker::OpenGLWorker(QOpenGLContext *share_ctx, OpenGLShaderCache *shader_cache, OpenGLTextureCache *texture_cache, VideoRenderFrameCache *frame_cache, QObject *parent) : VideoRenderWorker(frame_cache, parent), share_ctx_(share_ctx), ctx_(nullptr), functions_(nullptr), - shader_cache_(shader_cache) + shader_cache_(shader_cache), + texture_cache_(texture_cache) { surface_.create(); } @@ -95,8 +96,9 @@ void OpenGLWorker::FrameToValue(StreamPtr stream, FramePtr frame, NodeValueTable } } - OpenGLTexturePtr footage_tex = std::make_shared(); - footage_tex->Create(ctx_, frame); + VideoRenderingParams footage_params(frame->width(), frame->height(), stream->timebase(), frame->format(), video_params().mode()); + + OpenGLTextureCache::ReferencePtr footage_tex_ref = texture_cache_->Get(footage_params, frame->data()); if (video_params().mode() == olive::kOffline) { if (!color_processor->IsEnabled()) { @@ -104,27 +106,29 @@ void OpenGLWorker::FrameToValue(StreamPtr stream, FramePtr frame, NodeValueTable } // Create destination texture - OpenGLTexturePtr associated_tex = std::make_shared(); - associated_tex->Create(ctx_, footage_tex->width(), footage_tex->height(), footage_tex->format()); + OpenGLTextureCache::ReferencePtr associated_tex_ref = texture_cache_->Get(footage_params); // Set viewport for texture size - functions_->glViewport(0, 0, footage_tex->width(), footage_tex->height()); + functions_->glViewport(0, 0, footage_tex_ref->texture()->width(), footage_tex_ref->texture()->height()); - buffer_.Attach(associated_tex); + buffer_.Attach(associated_tex_ref->texture()); buffer_.Bind(); - footage_tex->Bind(); + footage_tex_ref->texture()->Bind(); + + functions_->glClearColor(0.0, 0.0, 0.0, 0.0); + functions_->glClear(GL_COLOR_BUFFER_BIT); // Blit old texture to new texture through OCIO shader color_processor->ProcessOpenGL(); - footage_tex->Release(); + footage_tex_ref->texture()->Release(); buffer_.Release(); buffer_.Detach(); - footage_tex = associated_tex; + footage_tex_ref = associated_tex_ref; } - table->Push(NodeParam::kTexture, QVariant::fromValue(footage_tex)); + table->Push(NodeParam::kTexture, QVariant::fromValue(footage_tex_ref)); } void OpenGLWorker::CloseInternal() @@ -150,13 +154,15 @@ void OpenGLWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase } // Create the output texture - OpenGLTexturePtr output = std::make_shared(); - output->Create(ctx_, video_params().effective_width(), video_params().effective_height(), video_params().format()); + OpenGLTextureCache::ReferencePtr output_ref = texture_cache_->Get(video_params()); - buffer_.Attach(output); + buffer_.Attach(output_ref->texture()); buffer_.Bind(); + functions_->glClearColor(0.0, 0.0, 0.0, 0.0); + functions_->glClear(GL_COLOR_BUFFER_BIT); + // Lock the shader so no other thread interferes as we set parameters and draw (and we don't interfere with any others) shader->Lock(); shader->bind(); @@ -206,11 +212,11 @@ void OpenGLWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase case NodeInput::kFootage: case NodeInput::kTexture: { - OpenGLTexturePtr texture = value.value(); + OpenGLTextureCache::ReferencePtr texture = value.value(); functions_->glActiveTexture(GL_TEXTURE0 + input_texture_count); - GLuint tex_id = texture ? texture->texture() : 0; + GLuint tex_id = texture ? texture->texture()->texture() : 0; functions_->glBindTexture(GL_TEXTURE_2D, tex_id); // Set value to bound texture @@ -228,8 +234,8 @@ void OpenGLWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase int res_param_location = shader->uniformLocation(QStringLiteral("%1_resolution").arg(input->id())); if (res_param_location > -1) { shader->setUniformValue(res_param_location, - static_cast(texture->width()), - static_cast(texture->height())); + static_cast(texture->texture()->width()), + static_cast(texture->texture()->height())); } } @@ -288,23 +294,23 @@ void OpenGLWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase buffer_.Detach(); - output_params->Push(NodeParam::kTexture, QVariant::fromValue(output)); + output_params->Push(NodeParam::kTexture, QVariant::fromValue(output_ref)); } void OpenGLWorker::TextureToBuffer(const QVariant &tex_in, QByteArray &buffer) { - OpenGLTexturePtr texture = tex_in.value(); + OpenGLTextureCache::ReferencePtr texture = tex_in.value(); PixelFormatInfo format_info = PixelService::GetPixelFormatInfo(video_params().format()); QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); - buffer_.Attach(texture); + buffer_.Attach(texture->texture()); f->glBindFramebuffer(GL_READ_FRAMEBUFFER, buffer_.buffer()); f->glReadPixels(0, 0, - texture->width(), - texture->height(), + texture->texture()->width(), + texture->texture()->height(), format_info.pixel_format, format_info.gl_pixel_type, buffer.data()); diff --git a/app/render/backend/opengl/openglworker.h b/app/render/backend/opengl/openglworker.h index 86bfd936c..84b1c2e1b 100644 --- a/app/render/backend/opengl/openglworker.h +++ b/app/render/backend/opengl/openglworker.h @@ -7,12 +7,14 @@ #include "../videorenderworker.h" #include "openglframebuffer.h" #include "openglshadercache.h" +#include "opengltexturecache.h" class OpenGLWorker : public VideoRenderWorker { Q_OBJECT public: OpenGLWorker(QOpenGLContext* share_ctx, OpenGLShaderCache* shader_cache, + OpenGLTextureCache* texture_cache, VideoRenderFrameCache* frame_cache, QObject* parent = nullptr); @@ -64,6 +66,8 @@ private: OpenGLShaderCache* shader_cache_; + OpenGLTextureCache* texture_cache_; + private slots: void FinishInit();