diff --git a/app/render/backend/exporter.cpp b/app/render/backend/exporter.cpp index 0d2e48e46..e63f02aa2 100644 --- a/app/render/backend/exporter.cpp +++ b/app/render/backend/exporter.cpp @@ -278,7 +278,8 @@ void Exporter::VideoHashesComplete() video_backend_->SetOperatingMode(VideoRenderWorker::kRenderOnly); video_backend_->SetOnlySignalLastFrameRequested(false); - connect(video_backend_, &VideoRenderBackend::CachedFrameReady, this, &Exporter::FrameRendered); + // FIXME: Exporting is now broken because of this + //connect(video_backend_, &VideoRenderBackend::CachedFrameReady, this, &Exporter::FrameRendered); foreach (const TimeRange& range, ranges) { video_backend_->InvalidateCache(range.in(), range.out()); diff --git a/app/render/backend/opengl/openglbackend.cpp b/app/render/backend/opengl/openglbackend.cpp index a79cc6d09..d0542e0a7 100644 --- a/app/render/backend/opengl/openglbackend.cpp +++ b/app/render/backend/opengl/openglbackend.cpp @@ -7,7 +7,6 @@ OpenGLBackend::OpenGLBackend(QObject *parent) : VideoRenderBackend(parent), - master_texture_(nullptr), proxy_(nullptr) { } @@ -49,17 +48,6 @@ bool OpenGLBackend::InitInternal() connect(processor, &OpenGLWorker::RequestRunNodeAccelerated, proxy_, &OpenGLProxy::RunNodeAccelerated, Qt::BlockingQueuedConnection); } - // Create master texture (the one sent to the viewer) - master_texture_ = std::make_shared(); - master_texture_->Create(QOpenGLContext::currentContext(), - params().effective_width(), - params().effective_height(), - params().format()); - - // Create copy buffer/pipeline - copy_buffer_.Create(QOpenGLContext::currentContext()); - copy_pipeline_ = OpenGLShader::CreateDefault(); - return true; } @@ -70,25 +58,9 @@ void OpenGLBackend::CloseInternal() proxy_ = nullptr; } - copy_buffer_.Destroy(); - copy_pipeline_ = nullptr; - master_texture_ = nullptr; - VideoRenderBackend::CloseInternal(); } -OpenGLTexturePtr OpenGLBackend::GetCachedFrameAsTexture(const rational &time) -{ - const char* cached_frame = GetCachedFrame(time); - - if (cached_frame) { - master_texture_->Upload(cached_frame); - return master_texture_; - } - - return nullptr; -} - bool OpenGLBackend::CompileInternal() { return true; @@ -98,52 +70,10 @@ void OpenGLBackend::DecompileInternal() { } -void OpenGLBackend::EmitCachedFrameReady(const rational &time, const QVariant &value, qint64 job_time) -{ - OpenGLTextureCache::ReferencePtr ref = value.value(); - OpenGLTexturePtr tex; - - if (ref && ref->texture()) { - tex = CopyTexture(ref->texture()); - } else { - tex = nullptr; - } - - emit CachedFrameReady(time, QVariant::fromValue(tex), job_time); -} - void OpenGLBackend::ParamsChangedEvent() { // If we're initiated, we need to recreate the texture. Otherwise this backend isn't active so it doesn't matter. if (IsInitiated()) { - master_texture_->Destroy(); - master_texture_->Create(QOpenGLContext::currentContext(), - params().effective_width(), - params().effective_height(), - params().format()); - proxy_->SetParameters(params()); } } - -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(); - - OpenGLRenderFunctions::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 f4b010230..43260b659 100644 --- a/app/render/backend/opengl/openglbackend.h +++ b/app/render/backend/opengl/openglbackend.h @@ -16,8 +16,6 @@ public: virtual ~OpenGLBackend() override; - OpenGLTexturePtr GetCachedFrameAsTexture(const rational& time); - protected: virtual bool InitInternal() override; @@ -27,18 +25,9 @@ protected: virtual void DecompileInternal() override; - virtual void EmitCachedFrameReady(const rational &time, const QVariant& value, qint64 job_time) override; - virtual void ParamsChangedEvent() override; private: - OpenGLTexturePtr CopyTexture(OpenGLTexturePtr input); - - OpenGLTexturePtr master_texture_; - - OpenGLFramebuffer copy_buffer_; - OpenGLShaderPtr copy_pipeline_; - OpenGLProxy* proxy_; }; diff --git a/app/render/backend/opengl/opengltexture.cpp b/app/render/backend/opengl/opengltexture.cpp index 1810b8704..03ebbfdb0 100644 --- a/app/render/backend/opengl/opengltexture.cpp +++ b/app/render/backend/opengl/opengltexture.cpp @@ -58,7 +58,7 @@ void OpenGLTexture::Create(QOpenGLContext *ctx, int width, int height, const Pix height_ = height; format_ = format; - connect(created_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy())); + connect(created_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()), Qt::DirectConnection); // Create main texture CreateInternal(created_ctx_, &texture_, data); @@ -83,26 +83,12 @@ void OpenGLTexture::Destroy() void OpenGLTexture::Bind() { - QOpenGLContext* context = QOpenGLContext::currentContext(); - - if (!context) { - qWarning() << "OpenGLTexture::Bind() called with an invalid context"; - return; - } - - context->functions()->glBindTexture(GL_TEXTURE_2D, texture_); + created_ctx_->functions()->glBindTexture(GL_TEXTURE_2D, texture_); } void OpenGLTexture::Release() { - QOpenGLContext* context = QOpenGLContext::currentContext(); - - if (!context) { - qWarning() << "OpenGLTexture::Release() called with an invalid context"; - return; - } - - context->functions()->glBindTexture(GL_TEXTURE_2D, 0); + created_ctx_->functions()->glBindTexture(GL_TEXTURE_2D, 0); } const int &OpenGLTexture::width() const @@ -132,26 +118,19 @@ void OpenGLTexture::Upload(const void *data) return; } - QOpenGLContext* context = QOpenGLContext::currentContext(); - - if (!context) { - qWarning() << "OpenGLTexture::Release() called with an invalid context"; - return; - } - Bind(); PixelFormat::Info info = PixelService::GetPixelFormatInfo(format_); - context->functions()->glTexSubImage2D(GL_TEXTURE_2D, - 0, - 0, - 0, - width_, - height_, - info.pixel_format, - info.gl_pixel_type, - data); + created_ctx_->functions()->glTexSubImage2D(GL_TEXTURE_2D, + 0, + 0, + 0, + width_, + height_, + info.pixel_format, + info.gl_pixel_type, + data); Release(); } diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp index 93fd9d566..a0e666cfb 100644 --- a/app/render/backend/renderbackend.cpp +++ b/app/render/backend/renderbackend.cpp @@ -202,6 +202,15 @@ void RenderBackend::RegenerateCacheID() CacheIDChangedEvent(cache_id_); } +bool RenderBackend::InitInternal() +{ + return true; +} + +void RenderBackend::CloseInternal() +{ +} + bool RenderBackend::CanRender() { return true; diff --git a/app/render/backend/renderbackend.h b/app/render/backend/renderbackend.h index db58f1cf9..8c09c464b 100644 --- a/app/render/backend/renderbackend.h +++ b/app/render/backend/renderbackend.h @@ -43,9 +43,9 @@ signals: protected: void RegenerateCacheID(); - virtual bool InitInternal() = 0; + virtual bool InitInternal(); - virtual void CloseInternal() = 0; + virtual void CloseInternal(); virtual bool CompileInternal() = 0; diff --git a/app/render/backend/videorenderbackend.cpp b/app/render/backend/videorenderbackend.cpp index d74bdb72d..1738f6e1b 100644 --- a/app/render/backend/videorenderbackend.cpp +++ b/app/render/backend/videorenderbackend.cpp @@ -42,17 +42,6 @@ VideoRenderBackend::VideoRenderBackend(QObject *parent) : connect(DiskManager::instance(), &DiskManager::DeletedFrame, this, &VideoRenderBackend::FrameRemovedFromDiskCache); } -bool VideoRenderBackend::InitInternal() -{ - ResizeCacheLoadBuffer(); - return true; -} - -void VideoRenderBackend::CloseInternal() -{ - cache_frame_load_buffer_.clear(); -} - void VideoRenderBackend::ConnectViewer(ViewerOutput *node) { connect(node, &ViewerOutput::VideoChangedBetween, this, &VideoRenderBackend::InvalidateCache); @@ -81,9 +70,6 @@ void VideoRenderBackend::SetParameters(const VideoRenderingParams& params) // Set new parameters params_ = params; - // Resize frame load buffer - ResizeCacheLoadBuffer(); - // Handle custom events from derivatives ParamsChangedEvent(); @@ -154,11 +140,6 @@ void VideoRenderBackend::ConnectWorkerToThis(RenderWorker *processor) connect(video_processor, &VideoRenderWorker::HashAlreadyExists, this, &VideoRenderBackend::ThreadHashAlreadyExists, Qt::QueuedConnection); } -void VideoRenderBackend::EmitCachedFrameReady(const rational &time, const QVariant &value, qint64 job_time) -{ - emit CachedFrameReady(time, value, job_time); -} - void VideoRenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range) { TimeRange invalidated(start_range, end_range); @@ -179,7 +160,7 @@ VideoRenderFrameCache *VideoRenderBackend::frame_cache() return &frame_cache_; } -const char *VideoRenderBackend::GetCachedFrame(const rational &time) +QString VideoRenderBackend::GetCachedFrame(const rational &time) { last_time_requested_ = time; @@ -204,30 +185,12 @@ const char *VideoRenderBackend::GetCachedFrame(const rational &time) QByteArray frame_hash = frame_cache_.TimeToHash(time); if (!frame_hash.isEmpty()) { - QString fn = frame_cache_.CachePathName(frame_hash, params_.format()); + DiskManager::instance()->Accessed(frame_hash); - if (QFileInfo::exists(fn)) { - auto in = OIIO::ImageInput::open(fn.toStdString()); - - if (in) { - DiskManager::instance()->Accessed(frame_hash); - - in->read_image(PixelService::GetPixelFormatInfo(params_.format()).oiio_desc, cache_frame_load_buffer_.data()); - - in->close(); - -#if OIIO_VERSION < 10903 - OIIO::ImageInput::destroy(in); -#endif - - return cache_frame_load_buffer_.constData(); - } else { - qWarning() << "OIIO Error:" << OIIO::geterror().c_str(); - } - } + return frame_cache_.CachePathName(frame_hash, params_.format()); } - return nullptr; + return QString(); } NodeInput *VideoRenderBackend::GetDependentInput() @@ -368,7 +331,7 @@ void VideoRenderBackend::TruncateFrameCacheLength(const rational &length) // If the playhead is past the length, update the viewer to a null texture because it won't be cached through the // queue, but will now be a null texture if (last_time_requested_ >= length) { - emit CachedFrameReady(last_time_requested_, QVariant(), QDateTime::currentMSecsSinceEpoch()); + emit CachedTimeReady(last_time_requested_, QDateTime::currentMSecsSinceEpoch()); } // Adjust queue for new invalidated range @@ -422,8 +385,3 @@ void VideoRenderBackend::Requeue() CacheNext(); } - -void VideoRenderBackend::ResizeCacheLoadBuffer() -{ - cache_frame_load_buffer_.resize(PixelService::GetBufferSize(params_.format(), params_.effective_width(), params_.effective_height())); -} diff --git a/app/render/backend/videorenderbackend.h b/app/render/backend/videorenderbackend.h index 5f151ff11..69ace2976 100644 --- a/app/render/backend/videorenderbackend.h +++ b/app/render/backend/videorenderbackend.h @@ -60,21 +60,13 @@ public: bool IsRendered(const rational& time) const; + QString GetCachedFrame(const rational& time); + VideoRenderFrameCache* frame_cache(); const VideoRenderingParams& params() const; protected: - /** - * @brief Allocate and start the multithreaded backend - */ - virtual bool InitInternal() override; - - /** - * @brief Terminate and deallocate the multithreaded backend - */ - virtual void CloseInternal() override; - struct HashTimeMapping { rational time; QByteArray hash; @@ -84,8 +76,6 @@ protected: virtual void DisconnectViewer(ViewerOutput* node) override; - const char *GetCachedFrame(const rational& time); - virtual NodeInput* GetDependentInput() override; virtual bool CanRender() override; @@ -101,8 +91,6 @@ protected: virtual void ConnectWorkerToThis(RenderWorker* processor) override; - virtual void EmitCachedFrameReady(const rational &time, const QVariant& value, qint64 job_time); - virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range) override; virtual void ParamsChangedEvent(); @@ -110,7 +98,6 @@ protected: VideoRenderWorker::OperatingMode operating_mode_; signals: - void CachedFrameReady(const rational& time, QVariant value, qint64 job_time); void CachedTimeReady(const rational& time, qint64 job_time); void RangeInvalidated(const TimeRange& range); @@ -124,12 +111,8 @@ private: void Requeue(); - void ResizeCacheLoadBuffer(); - VideoRenderingParams params_; - QByteArray cache_frame_load_buffer_; - VideoRenderFrameCache frame_cache_; TimeRangeList invalidated_; diff --git a/app/render/pixelservice.cpp b/app/render/pixelservice.cpp index 033e79a33..53e58437b 100644 --- a/app/render/pixelservice.cpp +++ b/app/render/pixelservice.cpp @@ -58,6 +58,21 @@ void PixelService::SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat } } +PixelFormat::Format PixelService::OIIOFormatToOliveFormat(OIIO::TypeDesc desc) +{ + if (desc == OIIO::TypeDesc::UINT8) { + return PixelFormat::PIX_FMT_RGBA8; + } else if (desc == OIIO::TypeDesc::UINT16) { + return PixelFormat::PIX_FMT_RGBA16U; + } else if (desc == OIIO::TypeDesc::HALF) { + return PixelFormat::PIX_FMT_RGBA16F; + } else if (desc == OIIO::TypeDesc::FLOAT) { + return PixelFormat::PIX_FMT_RGBA32F; + } + + return PixelFormat::PIX_FMT_INVALID; +} + PixelFormat::Info PixelService::GetPixelFormatInfo(const PixelFormat::Format &format) { PixelFormat::Info info; diff --git a/app/render/pixelservice.h b/app/render/pixelservice.h index ee84ed317..0a874f444 100644 --- a/app/render/pixelservice.h +++ b/app/render/pixelservice.h @@ -41,6 +41,8 @@ public: PixelFormat::Format GetConfiguredFormatForMode(RenderMode::Mode mode); void SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format); + static PixelFormat::Format OIIOFormatToOliveFormat(OIIO::TypeDesc desc); + /** * @brief Return a PixelFormatInfo containing information for a certain format * diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 559761529..25361fb34 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -83,7 +83,6 @@ ViewerWidget::ViewerWidget(QWidget *parent) : // Start background renderers video_renderer_ = new OpenGLBackend(this); - connect(video_renderer_, &VideoRenderBackend::CachedFrameReady, this, &ViewerWidget::RendererCachedFrame); connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, this, &ViewerWidget::RendererCachedTime); connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, ruler(), &TimeRuler::CacheTimeReady); connect(video_renderer_, &VideoRenderBackend::RangeInvalidated, ruler(), &TimeRuler::CacheInvalidatedRange); @@ -215,17 +214,16 @@ VideoRenderBackend *ViewerWidget::video_renderer() const return video_renderer_; } -void ViewerWidget::SetTexture(OpenGLTexturePtr tex) -{ - gl_widget_->SetTexture(tex); -} - void ViewerWidget::UpdateTextureFromNode(const rational& time) { - if (!GetConnectedNode()) { - SetTexture(nullptr); + if (!GetConnectedNode() || time >= GetConnectedNode()->Length()) { + gl_widget_->SetImage(QString()); } else { - SetTexture(video_renderer_->GetCachedFrameAsTexture(time)); + QString frame_fn = video_renderer_->GetCachedFrame(time); + + if (!frame_fn.isEmpty()) { + gl_widget_->SetImage(frame_fn); + } } } @@ -466,15 +464,6 @@ void ViewerWidget::PlaybackTimerUpdate() } } -void ViewerWidget::RendererCachedFrame(const rational &time, QVariant value, qint64 job_time) -{ - if (GetTime() == time && job_time > frame_cache_job_time_) { - frame_cache_job_time_ = job_time; - - SetTexture(value.value()); - } -} - void ViewerWidget::RendererCachedTime(const rational &time, qint64 job_time) { if (GetTime() == time && job_time > frame_cache_job_time_) { diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 17cd5c620..77ee1f967 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -72,15 +72,6 @@ public: VideoRenderBackend* video_renderer() const; public slots: - /** - * @brief Set the texture to draw and draw it - * - * Wrapper function for ViewerGLWidget::SetTexture(). - * - * @param tex - */ - void SetTexture(OpenGLTexturePtr tex); - void Play(); void Pause(); @@ -166,7 +157,6 @@ private: private slots: void PlaybackTimerUpdate(); - void RendererCachedFrame(const rational& time, QVariant value, qint64 job_time); void RendererCachedTime(const rational& time, qint64 job_time); void SizeChangedSlot(int width, int height); diff --git a/app/widget/viewer/viewerglwidget.cpp b/app/widget/viewer/viewerglwidget.cpp index 7798731c9..afcc0cb76 100644 --- a/app/widget/viewer/viewerglwidget.cpp +++ b/app/widget/viewer/viewerglwidget.cpp @@ -20,6 +20,8 @@ #include "viewerglwidget.h" +#include +#include #include #include #include @@ -27,10 +29,10 @@ #include "render/backend/opengl/openglrenderfunctions.h" #include "render/backend/opengl/openglshader.h" +#include "render/pixelservice.h" ViewerGLWidget::ViewerGLWidget(QWidget *parent) : QOpenGLWidget(parent), - texture_(0), ocio_lut_(0), color_manager_(nullptr) { @@ -68,6 +70,51 @@ void ViewerGLWidget::SetMatrix(const QMatrix4x4 &mat) update(); } +void ViewerGLWidget::SetImage(const QString &fn) +{ + OIIO::ImageBuf* in; + + if (fn.isEmpty()) { + // Backend had no filename + goto end; + } + + if (!QFileInfo::exists(fn)) { + goto end; + } + + in = new OIIO::ImageBuf(fn.toStdString()); + + if (in->read(0, 0, true)) { + + PixelFormat::Format image_format = PixelService::OIIOFormatToOliveFormat(in->spec().format); + + // Ensure the following texture operations are done in our context (in case we're in a separate window for instance) + makeCurrent(); + + if (!texture_.IsCreated() + || texture_.width() != in->spec().width + || texture_.height() != in->spec().height + || texture_.format() != image_format) { + texture_.Destroy(); + + texture_.Create(context(), in->spec().width, in->spec().height, image_format); + } + + texture_.Upload(in->localpixels()); + + doneCurrent(); + + } else { + qWarning() << "OIIO Error:" << OIIO::geterror().c_str(); + } + + delete in; + +end: + update(); +} + void ViewerGLWidget::SetOCIODisplay(const QString &display) { ocio_display_ = display; @@ -109,15 +156,6 @@ const QString &ViewerGLWidget::ocio_look() const return ocio_look_; } -void ViewerGLWidget::SetTexture(OpenGLTexturePtr tex) -{ - // Update the texture - texture_ = tex; - - // Paint the texture - update(); -} - void ViewerGLWidget::SetOCIOParameters(const QString &display, const QString &view, const QString &look) { ocio_display_ = display; @@ -144,15 +182,16 @@ void ViewerGLWidget::paintGL() f->glClear(GL_COLOR_BUFFER_BIT); // We only draw if we have a pipeline - if (!pipeline_ || !texture_) { + if (!pipeline_ || !texture_.IsCreated()) { return; } // Bind retrieved texture - f->glBindTexture(GL_TEXTURE_2D, texture_->texture()); + f->glBindTexture(GL_TEXTURE_2D, texture_.texture()); // Blit using the pipeline retrieved in initializeGL() - OpenGLRenderFunctions::OCIOBlit(pipeline_, ocio_lut_, true, matrix_); + //OpenGLRenderFunctions::OCIOBlit(pipeline_, ocio_lut_, true, matrix_); + OpenGLRenderFunctions::Blit(pipeline_, true, matrix_); // Release retrieved texture f->glBindTexture(GL_TEXTURE_2D, 0); @@ -240,7 +279,7 @@ void ViewerGLWidget::ContextCleanup() makeCurrent(); ClearOCIOLutTexture(); - + texture_.Destroy(); pipeline_ = nullptr; doneCurrent(); diff --git a/app/widget/viewer/viewerglwidget.h b/app/widget/viewer/viewerglwidget.h index 18f82bda1..b26414b2c 100644 --- a/app/widget/viewer/viewerglwidget.h +++ b/app/widget/viewer/viewerglwidget.h @@ -74,6 +74,11 @@ public: */ void SetMatrix(const QMatrix4x4& mat); + /** + * @brief Set an image to load and display on screen + */ + void SetImage(const QString& fn); + public slots: /** * @brief Set the texture to draw and draw it @@ -82,7 +87,7 @@ public slots: * * @param tex */ - void SetTexture(OpenGLTexturePtr tex); + //void SetTexture(OpenGLTexturePtr tex); void SetOCIOParameters(const QString& display, const QString& view, const QString& look); @@ -157,7 +162,7 @@ private: /** * @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL(). */ - OpenGLTexturePtr texture_; + OpenGLTexture texture_; /** * @brief Internal shader object to use as the pipeline shader