From 04d39e27a825db27bee182d930fe36cae12c2aae Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 21 Dec 2019 20:38:15 +1100 Subject: [PATCH] copy texture before signalling it Sending a texture directly from the texture cache is dangerous since once the reference is relinquished, it could be picked up and used by another thread. Copying the texture to a separate one takes a little extra time but lets the viewer remain in control of that texture. --- app/render/backend/opengl/openglbackend.cpp | 43 ++++++++++++++++++--- app/render/backend/opengl/openglbackend.h | 7 +++- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/app/render/backend/opengl/openglbackend.cpp b/app/render/backend/opengl/openglbackend.cpp index 09fe1bd6d..ee6b5f37f 100644 --- a/app/render/backend/opengl/openglbackend.cpp +++ b/app/render/backend/opengl/openglbackend.cpp @@ -6,7 +6,8 @@ #include "functions.h" OpenGLBackend::OpenGLBackend(QObject *parent) : - VideoRenderBackend(parent) + VideoRenderBackend(parent), + master_texture_(nullptr) { } @@ -31,7 +32,8 @@ bool OpenGLBackend::InitInternal() // Initiate one thread per CPU core for (int i=0;iSetParameters(params()); processors_.append(processor); } @@ -40,11 +42,17 @@ bool OpenGLBackend::InitInternal() master_texture_ = std::make_shared(); master_texture_->Create(share_ctx, params().effective_width(), params().effective_height(), params().format()); + // Create copy buffer/pipeline + copy_buffer_.Create(share_ctx); + copy_pipeline_ = OpenGLShader::CreateDefault(); + return true; } void OpenGLBackend::CloseInternal() { + copy_buffer_.Destroy(); + copy_pipeline_ = nullptr; master_texture_ = nullptr; } @@ -136,13 +144,36 @@ void OpenGLBackend::DecompileInternal() void OpenGLBackend::EmitCachedFrameReady(const rational &time, const QVariant &value) { - // FIXME: This texture is part of the texture cache and therefore volatile, we should probably copy it here instead OpenGLTextureCache::ReferencePtr ref = value.value(); - OpenGLTexturePtr tex = nullptr; + OpenGLTexturePtr tex; - if (ref) { - tex = ref->texture(); + if (ref && ref->texture()) { + tex = CopyTexture(ref->texture()); + } else { + tex = nullptr; } emit CachedFrameReady(time, QVariant::fromValue(tex)); } + +OpenGLTexturePtr OpenGLBackend::CopyTexture(OpenGLTexturePtr input) +{ + QOpenGLContext* ctx = QOpenGLContext::currentContext(); + + OpenGLTexturePtr copy = std::make_shared(); + copy->Create(ctx, input->width(), input->height(), input->format()); + + ctx->functions()->glViewport(0, 0, input->width(), input->height()); + + copy_buffer_.Attach(copy); + copy_buffer_.Bind(); + input->Bind(); + + olive::gl::Blit(copy_pipeline_); + + input->Release(); + copy_buffer_.Release(); + copy_buffer_.Detach(); + + return copy; +} diff --git a/app/render/backend/opengl/openglbackend.h b/app/render/backend/opengl/openglbackend.h index 74f3feec5..30638c00e 100644 --- a/app/render/backend/opengl/openglbackend.h +++ b/app/render/backend/opengl/openglbackend.h @@ -31,12 +31,17 @@ protected: virtual void EmitCachedFrameReady(const rational& time, const QVariant& value) override; private: - OpenGLTexturePtr master_texture_; + OpenGLTexturePtr CopyTexture(OpenGLTexturePtr input); OpenGLShaderCache shader_cache_; OpenGLTextureCache texture_cache_; + OpenGLTexturePtr master_texture_; + + OpenGLFramebuffer copy_buffer_; + OpenGLShaderPtr copy_pipeline_; + }; #endif // OPENGLBACKEND_H