]> git.sesse.net Git - kdenlive/commitdiff
Fix jittering issues when sending GL textures cross-thread.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 12 Jan 2014 13:00:50 +0000 (14:00 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Thu, 13 Mar 2014 21:16:54 +0000 (22:16 +0100)
When rendering into a texture on one thread and rendering _from_ it on another,
we need to properly synchronize the client state. Hook onto the OpenGL fences
that MLT set to properly wait for the rendering commands to be sent to the GPU,
which fixes the jittering we'd otherwise see, due to rendering old frames still
left in the textures because the new ones are not ready yet.

src/monitor.cpp
src/renderer.cpp
src/renderer.h
src/widgets/videoglwidget.cpp
src/widgets/videoglwidget.h

index 29a7a3d8463116cc0e280f3567667fa2332c7f49..5d562637deccb984bc0b68a258aecad329e0a764 100644 (file)
@@ -223,7 +223,7 @@ void Monitor::createOpenGlWidget(QWidget *parent, const QString &profile)
     m_glWidget->setImageAspectRatio(render->dar());
     m_glWidget->setBackgroundColor(KdenliveSettings::window_background());
     connect(render, SIGNAL(showImageSignal(QImage)), m_glWidget, SLOT(showImage(QImage)));
-    connect(render, SIGNAL(showImageSignal(GLuint)), m_glWidget, SLOT(showImage(GLuint)));
+    connect(render, SIGNAL(showImageSignal(Mlt::Frame*, GLuint)), m_glWidget, SLOT(showImage(Mlt::Frame*, GLuint)));
 }
 
 void Monitor::setupMenu(QMenu *goMenu, QAction *playZone, QAction *loopZone, QMenu *markerMenu, QAction *loopClip)
index 19067517d83c19d6adc93d3f30b1aa62653e231a..880a9653b21d3171ae16d3946057bb17a3fae283 100644 (file)
@@ -22,7 +22,6 @@
  *                                                                         *
  ***************************************************************************/
 
-
 #include "renderer.h"
 #include "kdenlivesettings.h"
 #include "kthumb.h"
@@ -1954,8 +1953,7 @@ void Render::showFrame(Mlt::Frame* frame)
         const uint8_t* image = frame->get_image(format, width, height);
         const GLuint* texnum = (GLuint *)image;
         if (format == mlt_image_glsl_texture) {
-          emit showImageSignal(*texnum);
-          delete frame;
+          emit showImageSignal(frame, *texnum);
         } else {
           QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied);
           memcpy(qimage.scanLine(0), image, width * height * 4);
index 43be7b8bffcb280978738ee5a017160a84281df3..6910f42706e0dd036e9e4d4a8bf25a9e02608a53 100644 (file)
@@ -33,6 +33,7 @@
 #include "definitions.h"
 #include "widgets/abstractmonitor.h"
 
+#include <GL/gl.h>
 #include <mlt/framework/mlt_types.h>
 
 #include <kurl.h>
@@ -486,7 +487,7 @@ signals:
      *
      * Used in Mac OS X. */
     void showImageSignal(QImage);
-    void showImageSignal(GLuint);
+    void showImageSignal(Mlt::Frame*, GLuint);
     void showAudioSignal(const QVector<double> &);
     void addClip(const KUrl &, stringMap);
     void checkSeeking();
index a37d529d79e50f17a9e3cfdacc362eef80820c48..3c62742e8072380fc3d820795055a7390d363a70 100644 (file)
 #include <GL/glu.h>
 #endif
 #include "widgets/videoglwidget.h"
+extern "C" {
+GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);
+}
+#include <mlt++/Mlt.h>
 
 #ifndef GL_TEXTURE_RECTANGLE_EXT
 #define GL_TEXTURE_RECTANGLE_EXT GL_TEXTURE_RECTANGLE_NV
@@ -40,7 +44,8 @@ VideoGLWidget::VideoGLWidget(QWidget *parent, QGLWidget *share)
     , m_image_width(0)
     , m_image_height(0)
     , m_texture(0)
-    , m_other_texture(0)
+    , m_frame(NULL)
+    , m_frame_texture(0)
     , m_display_ratio(4.0 / 3.0)
     , m_backgroundColor(Qt::gray)
 {  
@@ -53,6 +58,7 @@ VideoGLWidget::~VideoGLWidget()
     makeCurrent();
     if (m_texture)
         glDeleteTextures(1, &m_texture);
+    // m_frame will be cleaned up when the profile is closed by Render.
 }
 
 QSize VideoGLWidget::minimumSizeHint() const
@@ -147,12 +153,12 @@ void VideoGLWidget::paintGL()
         glEnd();
         glDisable(GL_TEXTURE_RECTANGLE_EXT);
     }
-    if (m_other_texture) {
+    if (m_frame_texture) {
 #ifdef Q_WS_MAC
                glClear(GL_COLOR_BUFFER_BIT);
 #endif
         glEnable(GL_TEXTURE_2D);
-        glBindTexture(GL_TEXTURE_2D, m_other_texture);
+        glBindTexture(GL_TEXTURE_2D, m_frame_texture);
         glBegin(GL_QUADS);
         glTexCoord2i(0, 0);
         glVertex2i(x, y);
@@ -174,7 +180,9 @@ void VideoGLWidget::showImage(const QImage &image)
     makeCurrent();
     if (m_texture)
         glDeleteTextures(1, &m_texture);
-    m_other_texture = 0;
+    delete m_frame;
+    m_frame = NULL;
+    m_frame_texture = 0;
 
     glPixelStorei(GL_UNPACK_ROW_LENGTH, m_image_width);
     glGenTextures(1, &m_texture);
@@ -186,14 +194,18 @@ void VideoGLWidget::showImage(const QImage &image)
     updateGL();
 }
 
-void VideoGLWidget::showImage(GLuint texnum)
+void VideoGLWidget::showImage(Mlt::Frame* frame, GLuint texnum)
 {
     makeCurrent();
+    GLsync sync = (GLsync) frame->get("movit.convert.fence");
+    glClientWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
     if (m_texture) {
         glDeleteTextures(1, &m_texture);
         m_texture = 0;
     }
-    m_other_texture = texnum;
+    delete m_frame;
+    m_frame = frame;
+    m_frame_texture = texnum;
 
     updateGL();
 }
index 918cb11734adb4d97fabd36125a162969b58246d..0598d133a35ccddfa906d8ec574a660dea8ba330 100644 (file)
 
 #include <QGLWidget>
 
+namespace Mlt {
+class Frame;
+}
+
 class VideoGLWidget : public QGLWidget
 {
     Q_OBJECT
@@ -40,7 +44,7 @@ public:
 
 public slots:
     void showImage(const QImage &image);
-    void showImage(GLuint);
+    void showImage(Mlt::Frame*, GLuint);
 
 protected:
     void initializeGL();
@@ -52,7 +56,9 @@ protected:
 private:
     int x, y, w, h;
     int m_image_width, m_image_height;
-    GLuint m_texture, m_other_texture;
+    GLuint m_texture;
+    Mlt::Frame *m_frame;
+    GLuint m_frame_texture;
     double m_display_ratio;
     QColor m_backgroundColor;
     Qt::WindowFlags m_baseFlags;