glsyncmeta: make context to wait and set sync explicit
[platform/upstream/gstreamer.git] / gst-libs / gst / gl / gstglsyncmeta.c
1 /*
2  * GStreamer
3  * Copyright (C) 2014 Matthew Waters <matthew@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 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  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gl.h"
26 #include "gstglsyncmeta.h"
27
28 #define GST_CAT_DEFAULT gst_gl_sync_meta_debug
29 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
30
31 #ifndef GL_SYNC_GPU_COMMANDS_COMPLETE
32 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
33 #endif
34 #ifndef GL_SYNC_FLUSH_COMMANDS_BIT
35 #define GL_SYNC_FLUSH_COMMANDS_BIT        0x00000001
36 #endif
37 #ifndef GL_TIMEOUT_EXPIRED
38 #define GL_TIMEOUT_EXPIRED 0x911B
39 #endif
40
41 GstGLSyncMeta *
42 gst_buffer_add_gl_sync_meta (GstGLContext * context, GstBuffer * buffer)
43 {
44   GstGLSyncMeta *meta;
45
46   g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL);
47
48   meta =
49       (GstGLSyncMeta *) gst_buffer_add_meta ((buffer), GST_GL_SYNC_META_INFO,
50       NULL);
51
52   if (!meta)
53     return NULL;
54
55   meta->context = gst_object_ref (context);
56   meta->glsync = NULL;
57
58   return meta;
59 }
60
61 static void
62 _set_sync_point (GstGLContext * context, GstGLSyncMeta * sync_meta)
63 {
64   const GstGLFuncs *gl = context->gl_vtable;
65
66   if (gl->FenceSync) {
67     if (sync_meta->glsync)
68       gl->DeleteSync (sync_meta->glsync);
69     sync_meta->glsync = gl->FenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
70     GST_LOG ("setting sync object %p", sync_meta->glsync);
71   } else {
72     gl->Flush ();
73   }
74 }
75
76 void
77 gst_gl_sync_meta_set_sync_point (GstGLSyncMeta * sync_meta,
78     GstGLContext * context)
79 {
80   gst_gl_context_thread_add (context,
81       (GstGLContextThreadFunc) _set_sync_point, sync_meta);
82 }
83
84 static void
85 _wait (GstGLContext * context, GstGLSyncMeta * sync_meta)
86 {
87   const GstGLFuncs *gl = context->gl_vtable;
88   GLenum res;
89
90   if (gl->ClientWaitSync) {
91     do {
92       GST_LOG ("waiting on sync object %p", sync_meta->glsync);
93       res =
94           gl->ClientWaitSync (sync_meta->glsync, GL_SYNC_FLUSH_COMMANDS_BIT,
95           1000000000 /* 1s */ );
96     } while (res == GL_TIMEOUT_EXPIRED);
97   }
98 }
99
100 void
101 gst_gl_sync_meta_wait (GstGLSyncMeta * sync_meta, GstGLContext * context)
102 {
103   if (sync_meta->context == context)
104     return;
105
106   if (sync_meta->glsync) {
107     gst_gl_context_thread_add (context,
108         (GstGLContextThreadFunc) _wait, sync_meta);
109   }
110 }
111
112 static gboolean
113 _gst_gl_sync_meta_transform (GstBuffer * dest, GstMeta * meta,
114     GstBuffer * buffer, GQuark type, gpointer data)
115 {
116   GstGLSyncMeta *dmeta, *smeta;
117
118   smeta = (GstGLSyncMeta *) meta;
119
120   if (GST_META_TRANSFORM_IS_COPY (type)) {
121     GstMetaTransformCopy *copy = data;
122
123     if (!copy->region) {
124       /* only copy if the complete data is copied as well */
125       dmeta = gst_buffer_add_gl_sync_meta (smeta->context, dest);
126
127       if (!dmeta)
128         return FALSE;
129
130       GST_DEBUG ("copy gl sync metadata");
131
132       dmeta->glsync = smeta->glsync;
133     }
134   }
135   return TRUE;
136 }
137
138 static void
139 _free_gl_sync_meta (GstGLContext * context, GstGLSyncMeta * sync_meta)
140 {
141   const GstGLFuncs *gl = context->gl_vtable;
142
143   if (sync_meta->glsync)
144     gl->DeleteSync (sync_meta->glsync);
145   sync_meta->glsync = NULL;
146 }
147
148 static void
149 _gst_gl_sync_meta_free (GstGLSyncMeta * sync_meta, GstBuffer * buffer)
150 {
151   if (sync_meta->glsync) {
152     gst_gl_context_thread_add (sync_meta->context,
153         (GstGLContextThreadFunc) _free_gl_sync_meta, sync_meta);
154   }
155   gst_object_unref (sync_meta->context);
156 }
157
158 static gboolean
159 _gst_gl_sync_meta_init (GstGLSyncMeta * sync_meta, gpointer params,
160     GstBuffer * buffer)
161 {
162   static volatile gsize _init;
163
164   if (g_once_init_enter (&_init)) {
165     GST_DEBUG_CATEGORY_INIT (gst_gl_sync_meta_debug, "glsyncmeta", 0,
166         "glsyncmeta");
167     g_once_init_leave (&_init, 1);
168   }
169
170   sync_meta->context = NULL;
171   sync_meta->glsync = NULL;
172
173   return TRUE;
174 }
175
176 GType
177 gst_gl_sync_meta_api_get_type (void)
178 {
179   static volatile GType type = 0;
180   static const gchar *tags[] = { NULL };
181
182   if (g_once_init_enter (&type)) {
183     GType _type = gst_meta_api_type_register ("GstGLSyncMetaAPI", tags);
184     g_once_init_leave (&type, _type);
185   }
186
187   return type;
188 }
189
190 const GstMetaInfo *
191 gst_gl_sync_meta_get_info (void)
192 {
193   static const GstMetaInfo *meta_info = NULL;
194
195   if (g_once_init_enter (&meta_info)) {
196     const GstMetaInfo *meta =
197         gst_meta_register (GST_GL_SYNC_META_API_TYPE, "GstGLSyncMeta",
198         sizeof (GstVideoMeta), (GstMetaInitFunction) _gst_gl_sync_meta_init,
199         (GstMetaFreeFunction) _gst_gl_sync_meta_free,
200         _gst_gl_sync_meta_transform);
201     g_once_init_leave (&meta_info, meta);
202   }
203
204   return meta_info;
205 }