]> git.sesse.net Git - mlt/blob - src/modules/qt/consumer_qglsl.cpp
A little debugging.
[mlt] / src / modules / qt / consumer_qglsl.cpp
1 /*
2  * consumer_qglsl.cpp
3  * Copyright (C) 2012-2014 Dan Dennedy <dan@dennedy.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "common.h"
21 #include <framework/mlt.h>
22 #include <QApplication>
23 #include <QGLWidget>
24 #include <QMutex>
25 #include <QWaitCondition>
26 #include <QtGlobal>
27
28 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
29
30 class GLWidget : public QGLWidget
31 {
32 private:
33         QGLWidget *renderContext;
34         bool isInitialized;
35         QMutex mutex;
36         QWaitCondition condition;
37
38 public:
39         GLWidget()
40 #ifdef Q_OS_MAC
41                 : QGLWidget()
42 #else
43                 : QGLWidget(0, 0, Qt::SplashScreen)
44 #endif
45                 , renderContext(0)
46                 , isInitialized(false)
47         {
48                 resize(0, 0);
49                 show();
50         }
51
52         ~GLWidget()
53         {
54                 delete renderContext;
55         }
56
57         bool createRenderContext()
58         {
59                 if (!isInitialized) {
60                         mutex.lock();
61                         condition.wait(&mutex);
62                         mutex.unlock();
63                 }
64                 if (!renderContext) {
65                         renderContext = new QGLWidget(0, this, Qt::SplashScreen);
66                         renderContext->resize(0, 0);
67                         renderContext->makeCurrent();
68                 }
69                 return renderContext->isValid();
70         }
71
72 protected:
73         void initializeGL()
74         {
75                 condition.wakeAll();
76                 isInitialized = true;
77         }
78 };
79
80 #else // Qt 5
81
82 #include <QThread>
83 #include <QOpenGLContext>
84 #include <QOffscreenSurface>
85
86 typedef void* ( *thread_function_t )( void* );
87
88 class RenderThread : public QThread
89 {
90 public:
91         RenderThread(thread_function_t function, void *data)
92                 : QThread(0)
93                 , m_function(function)
94                 , m_data(data)
95         {
96                 m_context = new QOpenGLContext;
97                 m_context->create();
98                 m_context->moveToThread(this);
99                 m_surface = new QOffscreenSurface();
100                 m_surface->create();
101         }
102         ~RenderThread()
103         {
104                 m_surface->destroy();
105                 delete m_surface;
106         }
107
108 protected:
109         void run()
110         {
111                 Q_ASSERT(m_context->isValid());
112                 m_context->makeCurrent(m_surface);
113                 m_function(m_data);
114                 m_context->doneCurrent();
115                 delete m_context;
116         }
117
118 private:
119         thread_function_t m_function;
120         void* m_data;
121         QOpenGLContext* m_context;
122         QOffscreenSurface* m_surface;
123 };
124
125 static void onThreadCreate(mlt_properties owner, mlt_consumer self,
126         RenderThread** thread, int* priority, thread_function_t function, void* data )
127 {
128         Q_UNUSED(owner)
129         Q_UNUSED(priority)
130         (*thread) = new RenderThread(function, data);
131         (*thread)->start();
132 }
133
134 static void onThreadJoin(mlt_properties owner, mlt_consumer self, RenderThread* thread)
135 {
136         Q_UNUSED(owner)
137         Q_UNUSED(self)
138         if (thread) {
139                 thread->quit();
140                 thread->wait();
141                 qApp->processEvents();
142                 delete thread;
143         }
144 }
145
146 #endif // Qt 5
147
148 static void onThreadStarted(mlt_properties owner, mlt_consumer consumer)
149 {
150         mlt_service service = MLT_CONSUMER_SERVICE(consumer);
151         mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
152         mlt_filter filter = (mlt_filter) mlt_properties_get_data(properties, "glslManager", NULL);
153         mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);
154
155         mlt_log_debug(service, "%s\n", __FUNCTION__);
156 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
157         GLWidget *widget = (GLWidget*) mlt_properties_get_data(properties, "GLWidget", NULL);
158         if (widget->createRenderContext()) {
159 #else
160         {
161 #endif
162                 mlt_events_fire(filter_properties, "init glsl", NULL);
163                 if (!mlt_properties_get_int(filter_properties, "glsl_supported")) {
164                         mlt_log_fatal(service,
165                                 "OpenGL Shading Language rendering is not supported on this machine.\n" );
166                         mlt_events_fire(properties, "consumer-fatal-error", NULL);
167                 }
168         }
169 }
170
171 static void onThreadStopped(mlt_properties owner, mlt_consumer consumer)
172 {
173         mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
174         mlt_filter filter = (mlt_filter) mlt_properties_get_data(properties, "glslManager", NULL);
175         mlt_events_fire(MLT_FILTER_PROPERTIES(filter), "close glsl", NULL);
176 }
177
178 static void onCleanup(mlt_properties owner, mlt_consumer consumer)
179 {
180 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
181         GLWidget* widget = (GLWidget*) mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "GLWidget", NULL);
182         delete widget;
183         mlt_properties_set_data(MLT_CONSUMER_PROPERTIES(consumer), "GLWidget", NULL, 0, NULL, NULL);
184         qApp->processEvents();
185 #endif
186 }
187
188 extern "C" {
189
190 mlt_consumer consumer_qglsl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
191 {
192         mlt_consumer consumer = mlt_factory_consumer(profile, "multi", arg);
193         if (consumer) {
194                 mlt_filter filter = mlt_factory_filter(profile, "glsl.manager", 0);
195                 if (filter) {
196                         mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
197                         mlt_properties_set_data(properties, "glslManager", filter, 0, (mlt_destructor) mlt_filter_close, NULL);
198                         mlt_events_register( properties, "consumer-cleanup", NULL );
199                         mlt_events_listen(properties, consumer, "consumer-thread-started", (mlt_listener) onThreadStarted);
200                         mlt_events_listen(properties, consumer, "consumer-thread-stopped", (mlt_listener) onThreadStopped);
201                         mlt_events_listen(properties, consumer, "consumer-cleanup", (mlt_listener) onCleanup);
202                         if (!createQApplicationIfNeeded(MLT_CONSUMER_SERVICE(consumer))) {
203                                 mlt_filter_close(filter);
204                                 mlt_consumer_close(consumer);
205                                 return NULL;
206                         }
207 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
208                         mlt_properties_set_data(properties, "GLWidget", new GLWidget, 0, NULL, NULL);
209 #else
210                         mlt_events_listen(properties, consumer, "consumer-thread-create", (mlt_listener) onThreadCreate);
211                         mlt_events_listen(properties, consumer, "consumer-thread-join", (mlt_listener) onThreadJoin);
212 #endif
213                         qApp->processEvents();
214                         return consumer;
215                 }
216                 mlt_consumer_close(consumer);
217         }
218         return NULL;
219 }
220
221 }