1 /* GStreamer
2 *
3 * Copyright (C) 2014 Matthew Waters <ystreet00@gmail.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 <gst/check/gstcheck.h>
26 #include <gst/gl/gstglfuncs.h>
27
28 #include <gst/gl/gl.h>
29
30 #include <stdio.h>
31
32 static GstGLDisplay *display;
33 static GstGLContext *context;
34 static GstGLWindow *window;
35 static GstGLUpload *upload;
36 static guint tex_id;
37 static GstGLShader *shader;
38 static GLint shader_attr_position_loc;
39 static GLint shader_attr_texture_loc;
40 static guint vbo, vbo_indices, vao;
41 static GstGLFramebuffer *fbo;
42 static GstGLMemory *fbo_tex;
43
44 static const GLfloat vertices[] = {
45 1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
46 -1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
47 -1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
48 1.0f, -1.0f, 0.0f, 1.0f, 1.0f
49 };
50
51 static GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
52
53 #define FORMAT GST_GL_RGBA
54 #define WIDTH 10
55 #define HEIGHT 10
56 #define RED 0xff, 0x00, 0x00, 0xff
57 #define GREEN 0x00, 0xff, 0x00, 0xff
58 #define BLUE 0x00, 0x00, 0xff, 0xff
59
60 static gchar rgba_data[] =
61 { RED, GREEN, BLUE, RED, GREEN, BLUE, RED, GREEN, BLUE, RED,
62 GREEN, BLUE, RED, GREEN, BLUE, RED, GREEN, BLUE, RED, GREEN,
63 BLUE, RED, GREEN, BLUE, RED, GREEN, BLUE, RED, GREEN, BLUE,
64 RED, RED, RED, RED, RED, RED, RED, RED, RED, RED,
65 GREEN, GREEN, GREEN, GREEN, GREEN, GREEN, GREEN, GREEN, GREEN, GREEN,
66 BLUE, BLUE, BLUE, BLUE, BLUE, BLUE, BLUE, BLUE, BLUE, BLUE,
67 RED, GREEN, BLUE, RED, GREEN, BLUE, RED, GREEN, BLUE, RED,
68 RED, GREEN, BLUE, RED, GREEN, BLUE, RED, GREEN, BLUE, RED,
69 RED, GREEN, BLUE, RED, GREEN, BLUE, RED, GREEN, BLUE, RED,
70 RED, GREEN, BLUE, RED, GREEN, BLUE, RED, GREEN, BLUE, RED
71 };
72
73 static void
setup(void)74 setup (void)
75 {
76 GError *error = NULL;
77
78 display = gst_gl_display_new ();
79 context = gst_gl_context_new (display);
80
81 gst_gl_context_create (context, 0, &error);
82 window = gst_gl_context_get_window (context);
83
84 fail_if (error != NULL, "Error creating context: %s\n",
85 error ? error->message : "Unknown Error");
86
87 upload = gst_gl_upload_new (context);
88 }
89
90 static void
_check_gl_error(GstGLContext * context,gpointer data)91 _check_gl_error (GstGLContext * context, gpointer data)
92 {
93 GLuint error = context->gl_vtable->GetError ();
94 fail_if (error != GL_NONE, "GL error 0x%x encountered during processing\n",
95 error);
96 }
97
98 static void
teardown(void)99 teardown (void)
100 {
101 gst_object_unref (upload);
102 gst_object_unref (window);
103
104 gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _check_gl_error,
105 NULL);
106 gst_object_unref (context);
107 gst_object_unref (display);
108 if (shader)
109 gst_object_unref (shader);
110 }
111
112 static void
_bind_buffer(GstGLContext * context)113 _bind_buffer (GstGLContext * context)
114 {
115 const GstGLFuncs *gl = context->gl_vtable;
116
117 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, vbo_indices);
118 gl->BindBuffer (GL_ARRAY_BUFFER, vbo);
119
120 /* Load the vertex position */
121 gl->VertexAttribPointer (shader_attr_position_loc, 3, GL_FLOAT, GL_FALSE,
122 5 * sizeof (GLfloat), (void *) 0);
123
124 /* Load the texture coordinate */
125 gl->VertexAttribPointer (shader_attr_texture_loc, 2, GL_FLOAT, GL_FALSE,
126 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat)));
127
128 gl->EnableVertexAttribArray (shader_attr_position_loc);
129 gl->EnableVertexAttribArray (shader_attr_texture_loc);
130 }
131
132 static void
_unbind_buffer(GstGLContext * context)133 _unbind_buffer (GstGLContext * context)
134 {
135 const GstGLFuncs *gl = context->gl_vtable;
136
137 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
138 gl->BindBuffer (GL_ARRAY_BUFFER, 0);
139
140 gl->DisableVertexAttribArray (shader_attr_position_loc);
141 gl->DisableVertexAttribArray (shader_attr_texture_loc);
142 }
143
144 static void
init(gpointer data)145 init (gpointer data)
146 {
147 const GstGLFuncs *gl = context->gl_vtable;
148 GError *error = NULL;
149
150 shader = gst_gl_shader_new_default (context, &error);
151 fail_if (shader == NULL, "failed to create shader object %s", error->message);
152
153 shader_attr_position_loc =
154 gst_gl_shader_get_attribute_location (shader, "a_position");
155 shader_attr_texture_loc =
156 gst_gl_shader_get_attribute_location (shader, "a_texcoord");
157
158 fbo = gst_gl_framebuffer_new_with_default_depth (context, WIDTH, HEIGHT);
159
160 {
161 GstGLMemoryAllocator *allocator;
162 GstGLVideoAllocationParams *params;
163 GstVideoInfo v_info;
164
165 allocator = gst_gl_memory_allocator_get_default (context);
166 gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGBA, WIDTH, HEIGHT);
167 params =
168 gst_gl_video_allocation_params_new (context, NULL, &v_info, 0, NULL,
169 GST_GL_TEXTURE_TARGET_2D, FORMAT);
170 fbo_tex =
171 (GstGLMemory *) gst_gl_base_memory_alloc ((GstGLBaseMemoryAllocator *)
172 allocator, (GstGLAllocationParams *) params);
173 gst_object_unref (allocator);
174 gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
175 }
176
177 if (!vbo) {
178 if (gl->GenVertexArrays) {
179 gl->GenVertexArrays (1, &vao);
180 gl->BindVertexArray (vao);
181 }
182
183 gl->GenBuffers (1, &vbo);
184 gl->BindBuffer (GL_ARRAY_BUFFER, vbo);
185 gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), vertices,
186 GL_STATIC_DRAW);
187
188 gl->GenBuffers (1, &vbo_indices);
189 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, vbo_indices);
190 gl->BufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices,
191 GL_STATIC_DRAW);
192
193 if (gl->GenVertexArrays) {
194 _bind_buffer (context);
195 gl->BindVertexArray (0);
196 }
197
198 gl->BindBuffer (GL_ARRAY_BUFFER, 0);
199 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
200 }
201 }
202
203 static void
deinit(gpointer data)204 deinit (gpointer data)
205 {
206 GstGLContext *context = data;
207 const GstGLFuncs *gl = context->gl_vtable;
208
209 if (vbo)
210 gl->DeleteBuffers (1, &vbo);
211 vbo = 0;
212 if (vbo_indices)
213 gl->DeleteBuffers (1, &vbo_indices);
214 vbo_indices = 0;
215 if (vao)
216 gl->DeleteVertexArrays (1, &vao);
217 vao = 0;
218
219 if (fbo)
220 gst_object_unref (fbo);
221 fbo = NULL;
222
223 if (fbo_tex)
224 gst_memory_unref (GST_MEMORY_CAST (fbo_tex));
225 fbo_tex = NULL;
226 }
227
228 static gboolean
blit_tex(gpointer data)229 blit_tex (gpointer data)
230 {
231 GstGLContext *context = data;
232 const GstGLFuncs *gl = context->gl_vtable;
233
234 gl->Clear (GL_COLOR_BUFFER_BIT);
235
236 gst_gl_shader_use (shader);
237
238 if (gl->GenVertexArrays)
239 gl->BindVertexArray (vao);
240 _bind_buffer (context);
241
242 gl->ActiveTexture (GL_TEXTURE0);
243 gl->BindTexture (GL_TEXTURE_2D, tex_id);
244 gst_gl_shader_set_uniform_1i (shader, "s_texture", 0);
245
246 gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
247
248 if (gl->GenVertexArrays)
249 gl->BindVertexArray (0);
250 else
251 _unbind_buffer (context);
252
253 return TRUE;
254 }
255
256 static void
draw_render(gpointer data)257 draw_render (gpointer data)
258 {
259 gst_gl_framebuffer_draw_to_texture (fbo, fbo_tex,
260 (GstGLFramebufferFunc) blit_tex, data);
261 }
262
GST_START_TEST(test_upload_data)263 GST_START_TEST (test_upload_data)
264 {
265 GstCaps *in_caps, *out_caps;
266 GstBuffer *inbuf, *outbuf;
267 GstMapInfo map_info;
268 gint res;
269 gint i = 0;
270
271 in_caps = gst_caps_from_string ("video/x-raw,format=RGBA,"
272 "width=10,height=10");
273 out_caps = gst_caps_from_string ("video/x-raw(memory:GLMemory),"
274 "format=RGBA,width=10,height=10");
275
276 gst_gl_upload_set_caps (upload, in_caps, out_caps);
277
278 inbuf = gst_buffer_new_wrapped_full (0, rgba_data, WIDTH * HEIGHT * 4,
279 0, WIDTH * HEIGHT * 4, NULL, NULL);
280
281 res = gst_gl_upload_perform_with_buffer (upload, inbuf, &outbuf);
282 fail_unless (res == GST_GL_UPLOAD_DONE, "Failed to upload buffer");
283 fail_unless (GST_IS_BUFFER (outbuf));
284 fail_unless (gst_buffer_get_video_meta (outbuf));
285 fail_unless (gst_buffer_get_gl_sync_meta (outbuf));
286
287 res = gst_buffer_map (outbuf, &map_info, GST_MAP_READ | GST_MAP_GL);
288 fail_if (res == FALSE, "Failed to map gl memory");
289
290 tex_id = *(guint *) map_info.data;
291
292 gst_buffer_unmap (outbuf, &map_info);
293
294 gst_gl_window_set_preferred_size (window, WIDTH, HEIGHT);
295 gst_gl_window_draw (window);
296
297 gst_gl_window_send_message (window, GST_GL_WINDOW_CB (init), context);
298
299 while (i < 2) {
300 gst_gl_window_send_message (window, GST_GL_WINDOW_CB (draw_render),
301 context);
302 i++;
303 }
304 gst_gl_window_send_message (window, GST_GL_WINDOW_CB (deinit), context);
305
306 gst_caps_unref (in_caps);
307 gst_caps_unref (out_caps);
308 gst_buffer_unref (inbuf);
309 gst_buffer_unref (outbuf);
310 }
311
312 GST_END_TEST;
313
GST_START_TEST(test_upload_gl_memory)314 GST_START_TEST (test_upload_gl_memory)
315 {
316 GstGLBaseMemoryAllocator *base_mem_alloc;
317 GstGLVideoAllocationParams *params;
318 GstBuffer *buffer, *outbuf;
319 GstGLMemory *gl_mem;
320 GstCaps *in_caps, *out_caps;
321 GstStructure *out_s;
322 GstVideoInfo in_info;
323 GstMapInfo map_info;
324 gint i = 0;
325 gint res;
326
327 base_mem_alloc =
328 GST_GL_BASE_MEMORY_ALLOCATOR (gst_allocator_find
329 (GST_GL_MEMORY_ALLOCATOR_NAME));
330
331 in_caps = gst_caps_from_string ("video/x-raw,format=RGBA,width=10,height=10");
332 gst_video_info_from_caps (&in_info, in_caps);
333
334 /* create GL buffer */
335 buffer = gst_buffer_new ();
336 params = gst_gl_video_allocation_params_new_wrapped_data (context, NULL,
337 &in_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D,
338 GST_GL_RGBA, rgba_data, NULL, NULL);
339 gl_mem = (GstGLMemory *) gst_gl_base_memory_alloc (base_mem_alloc,
340 (GstGLAllocationParams *) params);
341 gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
342
343 res =
344 gst_memory_map ((GstMemory *) gl_mem, &map_info,
345 GST_MAP_READ | GST_MAP_GL);
346 fail_if (res == FALSE, "Failed to map gl memory\n");
347 tex_id = *(guint *) map_info.data;
348 gst_memory_unmap ((GstMemory *) gl_mem, &map_info);
349
350 gst_buffer_append_memory (buffer, (GstMemory *) gl_mem);
351
352 /* at this point glupload hasn't received any buffers so can output anything */
353 out_caps = gst_gl_upload_transform_caps (upload, context,
354 GST_PAD_SINK, in_caps, NULL);
355 out_s = gst_caps_get_structure (out_caps, 0);
356 fail_unless (gst_structure_has_field_typed (out_s, "texture-target",
357 GST_TYPE_LIST));
358 gst_caps_unref (out_caps);
359
360 /* set some output caps without setting texture-target: this should trigger RECONFIGURE */
361 out_caps = gst_caps_from_string ("video/x-raw(memory:GLMemory),"
362 "format=RGBA,width=10,height=10");
363
364 /* set caps with texture-target not fixed. This should trigger RECONFIGURE. */
365 gst_gl_upload_set_caps (upload, in_caps, out_caps);
366 gst_caps_unref (out_caps);
367
368 /* push a texture-target=2D buffer */
369 res = gst_gl_upload_perform_with_buffer (upload, buffer, &outbuf);
370 fail_unless (res == GST_GL_UPLOAD_RECONFIGURE);
371 fail_if (outbuf);
372
373 /* now glupload has seen a 2D buffer and so wants to transform to that */
374 out_caps = gst_gl_upload_transform_caps (upload, context,
375 GST_PAD_SINK, in_caps, NULL);
376 out_s = gst_caps_get_structure (out_caps, 0);
377 fail_unless_equals_string (gst_structure_get_string (out_s, "texture-target"),
378 "2D");
379 gst_caps_unref (out_caps);
380
381 /* try setting the wrong type first tho */
382 out_caps = gst_caps_from_string ("video/x-raw(memory:GLMemory),"
383 "format=RGBA,width=10,height=10,texture-target=RECTANGLE");
384 gst_gl_upload_set_caps (upload, in_caps, out_caps);
385 gst_caps_unref (out_caps);
386
387 res = gst_gl_upload_perform_with_buffer (upload, buffer, &outbuf);
388 fail_unless (res == GST_GL_UPLOAD_RECONFIGURE);
389 fail_if (outbuf);
390
391 /* finally do set the correct texture-target */
392 out_caps = gst_caps_from_string ("video/x-raw(memory:GLMemory),"
393 "format=RGBA,width=10,height=10,texture-target=2D");
394 gst_gl_upload_set_caps (upload, in_caps, out_caps);
395 gst_caps_unref (out_caps);
396
397 res = gst_gl_upload_perform_with_buffer (upload, buffer, &outbuf);
398 fail_unless (res == GST_GL_UPLOAD_DONE, "Failed to upload buffer");
399 fail_unless (GST_IS_BUFFER (outbuf));
400
401 gst_gl_window_set_preferred_size (window, WIDTH, HEIGHT);
402 gst_gl_window_draw (window);
403 gst_gl_window_send_message (window, GST_GL_WINDOW_CB (init), context);
404
405 while (i < 2) {
406 gst_gl_window_send_message (window, GST_GL_WINDOW_CB (draw_render),
407 context);
408 i++;
409 }
410 gst_gl_window_send_message (window, GST_GL_WINDOW_CB (deinit), context);
411
412 gst_caps_unref (in_caps);
413 gst_buffer_unref (buffer);
414 gst_buffer_unref (outbuf);
415 gst_object_unref (base_mem_alloc);
416 }
417
418 GST_END_TEST;
419
420
421 static Suite *
gst_gl_upload_suite(void)422 gst_gl_upload_suite (void)
423 {
424 Suite *s = suite_create ("GstGLUpload");
425 TCase *tc_chain = tcase_create ("upload");
426
427 suite_add_tcase (s, tc_chain);
428 tcase_add_checked_fixture (tc_chain, setup, teardown);
429 tcase_add_test (tc_chain, test_upload_data);
430 tcase_add_test (tc_chain, test_upload_gl_memory);
431
432 return s;
433 }
434
435 GST_CHECK_MAIN (gst_gl_upload);
436