summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xgl-novice/src/gl-simple-dmabuf-egl/CMakeLists.txt39
-rw-r--r--gl-novice/src/gl-simple-dmabuf-egl/gl-simple-dmabuf-egl-description.txt25
-rw-r--r--gl-novice/src/gl-simple-dmabuf-egl/gl-simple-dmabuf-egl.c859
3 files changed, 923 insertions, 0 deletions
diff --git a/gl-novice/src/gl-simple-dmabuf-egl/CMakeLists.txt b/gl-novice/src/gl-simple-dmabuf-egl/CMakeLists.txt
new file mode 100755
index 0000000..9e439ae
--- /dev/null
+++ b/gl-novice/src/gl-simple-dmabuf-egl/CMakeLists.txt
@@ -0,0 +1,39 @@
+CMAKE_MINIMUM_REQUIRED (VERSION 2.8)
+INCLUDE(FindPkgConfig)
+
+SET(TEST_NAME "gl-simple-dmabuf-egl")
+
+SET(SRCS
+ ${TEST_NAME}.c
+
+#please write your test sources
+)
+
+pkg_check_modules(pkgs REQUIRED
+ glesv2
+ egl
+ libtbm
+ wayland-egl
+ wayland-egl-tizen
+ wayland-client
+ glib-2.0
+ ttrace
+ #please write require package
+)
+
+ADD_DEFINITIONS(${pkgs_CFLAGS} -g)
+
+include_directories("../../include")
+
+ADD_EXECUTABLE(${TEST_NAME} ${TEST_NAME}.c ${SRCS})
+TARGET_LINK_LIBRARIES(${TEST_NAME} ${pkgs_LDFLAGS} -lm)
+
+INSTALL(PROGRAMS ${TEST_NAME}
+ DESTINATION /usr/local/bin/novice/${TEST_NAME}
+)
+INSTALL(FILES ${TEST_NAME}-description.txt
+ DESTINATION /usr/local/bin/novice/${TEST_NAME}
+)
+
+SET(CMAKE_C_FLAGS " -fPIE -Wall")
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib -pie")
diff --git a/gl-novice/src/gl-simple-dmabuf-egl/gl-simple-dmabuf-egl-description.txt b/gl-novice/src/gl-simple-dmabuf-egl/gl-simple-dmabuf-egl-description.txt
new file mode 100644
index 0000000..b82d5c7
--- /dev/null
+++ b/gl-novice/src/gl-simple-dmabuf-egl/gl-simple-dmabuf-egl-description.txt
@@ -0,0 +1,25 @@
+Title
+#Please write your test program Title
+#==========================================================================
+GL resize test.
+
+Date
+#Please write Date
+#==========================================================================
+2017-07-26
+
+Author
+#Please write Author
+#==========================================================================
+Joonbum Ko
+
+Module
+#Please write your test program Module
+#==========================================================================
+GL
+
+Description
+#Please write your test program detail description
+#==========================================================================
+It is a test sample that sleep one second after rendering one frame and proceeds
+to resize the next frame.
diff --git a/gl-novice/src/gl-simple-dmabuf-egl/gl-simple-dmabuf-egl.c b/gl-novice/src/gl-simple-dmabuf-egl/gl-simple-dmabuf-egl.c
new file mode 100644
index 0000000..41bb054
--- /dev/null
+++ b/gl-novice/src/gl-simple-dmabuf-egl/gl-simple-dmabuf-egl.c
@@ -0,0 +1,859 @@
+/*
+ * Copyright © 2011 Benjamin Franzke
+ * Copyright © 2010 Intel Corporation
+ * Copyright © 2014,2018 Collabora Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <wayland-client.h>
+#include <wayland-egl.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <tbm_bufmgr.h>
+#include <tbm_bo.h>
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+
+#include "egl-helpers.h"
+#include "helpers.h"
+
+
+#define BUFFER_FORMAT TBM_FORMAT_ARGB8888
+#define MAX_BUFFER_PLANES 4
+
+struct display {
+ struct wl_display *display;
+ struct wl_registry *registry;
+ struct wl_compositor *compositor;
+ struct wl_shell *shell;
+
+ struct {
+ EGLDisplay display;
+ EGLContext context;
+ EGLConfig conf;
+ bool has_dma_buf_import_modifiers;
+ //PFNEGLQUERYDMABUFMODIFIERSEXTPROC query_dma_buf_modifiers;
+ PFNEGLCREATEIMAGEKHRPROC create_image;
+ PFNEGLDESTROYIMAGEKHRPROC destroy_image;
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
+ } egl;
+
+ tbm_bufmgr bufmgr;
+};
+
+struct buffer {
+ struct display *display;
+
+ tbm_surface_h tbm_surface;
+
+ int width;
+ int height;
+ int format;
+ uint64_t modifier;
+ int plane_count;
+ int dmabuf_fds[MAX_BUFFER_PLANES];
+ uint32_t strides[MAX_BUFFER_PLANES];
+ uint32_t offsets[MAX_BUFFER_PLANES];
+
+ EGLImageKHR egl_image;
+ GLuint gl_texture;
+ GLuint gl_fbo;
+};
+
+#define NUM_BUFFERS 3
+
+struct window {
+ struct display *display;
+ int width, height;
+ struct wl_surface *surface;
+ struct wl_shell_surface *shell_surface;
+ struct buffer buffers[NUM_BUFFERS];
+ struct wl_callback *callback;
+ struct wl_egl_window *native;
+ bool initialized;
+ bool wait_for_configure;
+ struct {
+ GLuint program;
+ GLuint pos;
+ GLuint color;
+ GLuint offset_uniform;
+ } gl;
+
+ struct {
+ EGLSurface surface;
+ } egl;
+
+ int current_idx;
+};
+
+static sig_atomic_t running = 1;
+
+static void
+redraw(void *data, struct wl_callback *callback, uint32_t time);
+
+
+static void
+buffer_free(struct buffer *buf)
+{
+ if (buf->gl_fbo)
+ glDeleteFramebuffers(1, &buf->gl_fbo);
+
+ if (buf->gl_texture)
+ glDeleteTextures(1, &buf->gl_texture);
+
+ if (buf->egl_image) {
+ buf->display->egl.destroy_image(buf->display->egl.display,
+ buf->egl_image);
+ }
+
+ if (buf->tbm_surface)
+ tbm_surface_destroy(buf->tbm_surface);
+
+}
+
+static bool
+create_fbo_for_buffer(struct display *display, struct buffer *buffer)
+{
+ static const int general_attribs = 3;
+ static const int plane_attribs = 5;
+ static const int entries_per_attrib = 2;
+ EGLint attribs[(general_attribs + plane_attribs * MAX_BUFFER_PLANES) *
+ entries_per_attrib + 1];
+ unsigned int atti = 0;
+
+ attribs[atti++] = EGL_WIDTH;
+ attribs[atti++] = buffer->width;
+ attribs[atti++] = EGL_HEIGHT;
+ attribs[atti++] = buffer->height;
+ attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
+ attribs[atti++] = buffer->format;
+
+#define ADD_PLANE_ATTRIBS(plane_idx) { \
+ attribs[atti++] = EGL_DMA_BUF_PLANE ## plane_idx ## _FD_EXT; \
+ attribs[atti++] = buffer->dmabuf_fds[plane_idx]; \
+ attribs[atti++] = EGL_DMA_BUF_PLANE ## plane_idx ## _OFFSET_EXT; \
+ attribs[atti++] = (int) buffer->offsets[plane_idx]; \
+ attribs[atti++] = EGL_DMA_BUF_PLANE ## plane_idx ## _PITCH_EXT; \
+ attribs[atti++] = (int) buffer->strides[plane_idx]; \
+ }
+
+ if (buffer->plane_count > 0)
+ ADD_PLANE_ATTRIBS(0);
+
+ if (buffer->plane_count > 1)
+ ADD_PLANE_ATTRIBS(1);
+
+ if (buffer->plane_count > 2)
+ ADD_PLANE_ATTRIBS(2);
+
+#undef ADD_PLANE_ATTRIBS
+
+ attribs[atti] = EGL_NONE;
+
+ assert(atti < ARRAY_LENGTH(attribs));
+
+ buffer->egl_image = display->egl.create_image(display->egl.display,
+ EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT,
+ NULL, attribs);
+ if (buffer->egl_image == EGL_NO_IMAGE_KHR) {
+ fprintf(stderr, "EGLImageKHR creation failed\n");
+ return false;
+ }
+
+ //eglMakeCurrent(display->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ // display->egl.context);
+
+ glGenTextures(1, &buffer->gl_texture);
+ glBindTexture(GL_TEXTURE_2D, buffer->gl_texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ display->egl.image_target_texture_2d(GL_TEXTURE_2D, buffer->egl_image);
+
+ glGenFramebuffers(1, &buffer->gl_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, buffer->gl_fbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, buffer->gl_texture, 0);
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ fprintf(stderr, "FBO creation failed\n");
+ return false;
+ }
+
+ return true;
+
+ return true;
+}
+
+static int
+create_tbm_buffer(struct display *display, struct buffer *buffer,
+ int width, int height, uint32_t opts)
+{
+ int i = 0;
+
+ buffer->display = display;
+ buffer->width = width;
+ buffer->height = height;
+ buffer->format = BUFFER_FORMAT;
+
+ if (buffer->tbm_surface == NULL)
+ buffer->tbm_surface = tbm_surface_create(buffer->width,
+ buffer->height,
+ buffer->format);
+
+ if (!buffer->tbm_surface) {
+ fprintf(stderr, "create_tbm_buffer failed\n");
+ goto error;
+ }
+
+ buffer->plane_count = tbm_surface_internal_get_num_planes(buffer->format);
+
+ for (i = 0; i < buffer->plane_count; ++i) {
+ int bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer->tbm_surface, i);
+ tbm_bo bo = tbm_surface_internal_get_bo(buffer->tbm_surface, bo_idx);
+
+ buffer->dmabuf_fds[i] = tbm_bo_export_fd(bo);
+
+ tbm_surface_internal_get_plane_data(buffer->tbm_surface, i,
+ NULL,
+ &buffer->offsets[i],
+ &buffer->strides[i]);
+ }
+
+ if (!create_fbo_for_buffer(display, buffer))
+ goto error;
+
+ return 0;
+
+error:
+ buffer_free(buffer);
+ return -1;
+}
+
+static void
+handle_ping(void *data, struct wl_shell_surface *shell_surface,
+ uint32_t serial)
+{
+ wl_shell_surface_pong(shell_surface, serial);
+}
+
+static void
+handle_configure(void *data, struct wl_shell_surface *shell_surface,
+ uint32_t edges, int32_t width, int32_t height)
+{
+ struct window *window = data;
+
+ if (window->initialized && window->wait_for_configure)
+ redraw(window, NULL, 0);
+ window->wait_for_configure = false;
+
+}
+
+static void
+handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
+{
+}
+
+static const struct wl_shell_surface_listener shell_surface_listener = {
+ handle_ping,
+ handle_configure,
+ handle_popup_done
+};
+
+
+static const char *vert_shader_text =
+ "uniform float offset;\n"
+ "attribute vec4 pos;\n"
+ "attribute vec4 color;\n"
+ "varying vec4 v_color;\n"
+ "void main() {\n"
+ " gl_Position = pos + vec4(offset, offset, 0.0, 0.0);\n"
+ " v_color = color;\n"
+ "}\n";
+
+static const char *frag_shader_text =
+ "precision mediump float;\n"
+ "varying vec4 v_color;\n"
+ "void main() {\n"
+ " gl_FragColor = v_color;\n"
+ "}\n";
+
+
+static GLuint
+create_shader(const char *source, GLenum shader_type)
+{
+ GLuint shader;
+ GLint status;
+
+ shader = glCreateShader(shader_type);
+ assert(shader != 0);
+
+ glShaderSource(shader, 1, (const char **) &source, NULL);
+ glCompileShader(shader);
+
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+ if (!status) {
+ char log[1000];
+ GLsizei len;
+ glGetShaderInfoLog(shader, 1000, &len, log);
+ fprintf(stderr, "Error: compiling %s: %.*s\n",
+ shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
+ len, log);
+ return 0;
+ }
+
+ return shader;
+}
+
+static GLuint
+create_and_link_program(GLuint vert, GLuint frag)
+{
+ GLint status;
+ GLuint program = glCreateProgram();
+
+ glAttachShader(program, vert);
+ glAttachShader(program, frag);
+ glLinkProgram(program);
+
+ glGetProgramiv(program, GL_LINK_STATUS, &status);
+ if (!status) {
+ char log[1000];
+ GLsizei len;
+ glGetProgramInfoLog(program, 1000, &len, log);
+ fprintf(stderr, "Error: linking:\n%.*s\n", len, log);
+ return 0;
+ }
+
+ return program;
+}
+
+static bool
+window_set_up_gl(struct window *window)
+{
+ EGLBoolean ret;
+
+ assert(ret);
+
+ GLuint vert = create_shader(vert_shader_text,
+ GL_VERTEX_SHADER);
+ GLuint frag = create_shader(frag_shader_text,
+ GL_FRAGMENT_SHADER);
+
+ window->gl.program = create_and_link_program(vert, frag);
+
+ glDeleteShader(vert);
+ glDeleteShader(frag);
+
+ window->gl.pos = glGetAttribLocation(window->gl.program, "pos");
+ window->gl.color = glGetAttribLocation(window->gl.program, "color");
+
+ glUseProgram(window->gl.program);
+
+ window->gl.offset_uniform =
+ glGetUniformLocation(window->gl.program, "offset");
+
+ return window->gl.program != 0;
+}
+
+static void
+destroy_window(struct window *window)
+{
+ int i;
+
+ eglMakeCurrent(window->display->egl.display,
+ EGL_NO_SURFACE,
+ EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+
+ if (window->egl.surface)
+ platform_destroy_egl_surface(window->display->egl.display,
+ window->egl.surface);
+
+ if (window->native)
+ wl_egl_window_destroy(window->native);
+
+ if (window->gl.program)
+ glDeleteProgram(window->gl.program);
+
+ if (window->callback)
+ wl_callback_destroy(window->callback);
+
+ for (i = 0; i < NUM_BUFFERS; i++) {
+ buffer_free(&window->buffers[i]);
+ }
+
+ wl_shell_surface_destroy(window->shell_surface);
+
+ wl_surface_destroy(window->surface);
+ free(window);
+}
+
+static struct window *
+create_window(struct display *display, int width, int height, int opts)
+{
+ struct window *window;
+ int i;
+ int ret;
+
+ window = (struct window *)calloc(1, sizeof(struct window));
+ if (!window)
+ return NULL;
+
+ window->callback = NULL;
+ window->display = display;
+ window->width = width;
+ window->height = height;
+ window->current_idx = 0;
+ window->surface = wl_compositor_create_surface(display->compositor);
+
+ if (display->shell) {
+ window->shell_surface = wl_shell_get_shell_surface(display->shell,
+ window->surface);
+
+ assert(window->shell_surface);
+
+ wl_shell_surface_add_listener(window->shell_surface,
+ &shell_surface_listener, window);
+
+ wl_shell_surface_set_title(window->shell_surface, "simple-dmabuf-egl");
+
+ window->wait_for_configure = true;
+
+ window->native = wl_egl_window_create(window->surface,
+ window->width,
+ window->height);
+ window->egl.surface =
+ platform_create_egl_surface(display->egl.display,
+ display->egl.conf,
+ window->native, NULL);
+ ret = eglMakeCurrent(window->display->egl.display, window->egl.surface,
+ window->egl.surface, window->display->egl.context);
+ assert(ret);
+
+ } else {
+ assert(0);
+ }
+
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ window->buffers[i].tbm_surface = NULL;
+ }
+
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ ret = create_tbm_buffer(display, &window->buffers[i],
+ width, height, opts);
+
+ if (ret < 0)
+ goto error;
+ }
+
+ if (!window_set_up_gl(window))
+ goto error;
+
+ return window;
+
+error:
+ if (window)
+ destroy_window(window);
+
+ return NULL;
+}
+
+static struct buffer *
+window_next_buffer(struct window *window)
+{
+ int i = window->current_idx;
+
+ window->current_idx++;
+
+ if (window->current_idx >= NUM_BUFFERS) {
+ window->current_idx = 0;
+ }
+
+ return &window->buffers[i];
+}
+
+static const struct wl_callback_listener frame_listener;
+
+/* Renders a square moving from the lower left corner to the
+ * upper right corner of the window. The square's vertices have
+ * the following colors:
+ *
+ * green +-----+ yellow
+ * | |
+ * | |
+ * red +-----+ blue
+ */
+static void
+render(struct window *window, struct buffer *buffer)
+{
+ /* Complete a movement iteration in 5000 ms. */
+ static const uint64_t iteration_ms = 5000;
+ static const GLfloat verts[4][2] = {
+ { -0.5, -0.5 },
+ { -0.5, 0.5 },
+ { 0.5, -0.5 },
+ { 0.5, 0.5 }
+ };
+ static const GLfloat colors[4][3] = {
+ { 1, 0, 0 },
+ { 0, 1, 0 },
+ { 0, 0, 1 },
+ { 1, 1, 0 }
+ };
+ GLfloat offset;
+ struct timeval tv;
+ uint64_t time_ms;
+
+ gettimeofday(&tv, NULL);
+ time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+
+ /* Split time_ms in repeating windows of [0, iteration_ms) and map them
+ * to offsets in the [-0.5, 0.5) range. */
+ offset = (time_ms % iteration_ms) / (float) iteration_ms - 0.5;
+
+ /* Direct all GL draws to the buffer through the FBO */
+ glBindFramebuffer(GL_FRAMEBUFFER, buffer->gl_fbo);
+
+ glViewport(0, 0, window->width, window->height);
+
+ glUniform1f(window->gl.offset_uniform, offset);
+
+ glClearColor(0.0,0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
+ glVertexAttribPointer(window->gl.color, 3, GL_FLOAT, GL_FALSE, 0, colors);
+ glEnableVertexAttribArray(window->gl.pos);
+ glEnableVertexAttribArray(window->gl.color);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ glDisableVertexAttribArray(window->gl.pos);
+ glDisableVertexAttribArray(window->gl.color);
+
+ glFinish();
+
+ {
+ char name[50];
+ snprintf(name, sizeof(name), "tbm_surface_%p_%d_x_%d", buffer->tbm_surface, buffer->width, buffer->height);
+ tbm_surface_internal_capture_buffer(buffer->tbm_surface, "/tmp/gl-novice", name, "png");
+ }
+
+}
+
+static void
+redraw(void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct window *window = data;
+ struct buffer *buffer;
+ char name[50];
+ int ret;
+
+ buffer = window_next_buffer(window);
+ if (!buffer) {
+ fprintf(stderr,
+ !callback ? "Failed to create the first buffer.\n" :
+ "All buffers busy at redraw(). Server bug?\n");
+ abort();
+ }
+ ret = eglMakeCurrent(window->display->egl.display, window->egl.surface,
+ window->egl.surface, window->display->egl.context);
+ assert(ret);
+
+ render(window, buffer);
+
+ //window->callback = wl_surface_frame(window->surface);
+ //wl_callback_add_listener(window->callback, &frame_listener, window);
+
+#if 0
+ //glFinish();
+
+ snprintf(name, sizeof(name), "tbm_surface_%p_%d_x_%d", buffer->tbm_surface, buffer->width, buffer->height);
+ tbm_surface_internal_capture_buffer(buffer->tbm_surface, "/tmp/gl-novice", name, "png");
+#else
+ ret = eglSwapBuffers(buffer->display->egl.display, window->egl.surface);
+ if (!ret)
+ printf("Failed to succeed eglSwapBuffers\n");
+#endif
+}
+
+static const struct wl_callback_listener frame_listener = {
+ redraw
+};
+
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface, uint32_t version)
+{
+ struct display *d = data;
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ d->compositor =
+ wl_registry_bind(registry,
+ id, &wl_compositor_interface, 1);
+ } else if (strcmp(interface, "wl_shell") == 0) {
+ d->shell = wl_registry_bind(registry, id,
+ &wl_shell_interface, 1);
+ }
+}
+
+static void
+registry_handle_global_remove(void *data, struct wl_registry *registry,
+ uint32_t name)
+{
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ registry_handle_global_remove
+};
+
+static void
+destroy_display(struct display *display)
+{
+ printf("destroy_display %d\n", display->egl.display);
+ if (display->egl.context != EGL_NO_CONTEXT)
+ eglDestroyContext(display->egl.display, display->egl.context);
+
+ if (display->egl.display != EGL_NO_DISPLAY)
+ eglTerminate(display->egl.display);
+
+ if (display->shell)
+ wl_shell_destroy(display->shell);
+
+ if (display->compositor)
+ wl_compositor_destroy(display->compositor);
+
+ if (display->registry)
+ wl_registry_destroy(display->registry);
+
+ if (display->bufmgr)
+ tbm_bufmgr_deinit(display->bufmgr);
+
+ if (display->display) {
+ wl_display_flush(display->display);
+ wl_display_disconnect(display->display);
+ }
+
+ free(display);
+}
+
+static bool
+display_set_up_egl(struct display *display)
+{
+ static const EGLint context_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ EGLint major, minor, ret, count;
+ const char *egl_extensions = NULL;
+
+ EGLint config_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 1,
+ EGL_GREEN_SIZE, 1,
+ EGL_BLUE_SIZE, 1,
+ EGL_ALPHA_SIZE, 1,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+
+ display->egl.display = eglGetDisplay(display->display);
+
+ if (display->egl.display == EGL_NO_DISPLAY) {
+ fprintf(stderr, "Failed to create EGLDisplay\n");
+ goto error;
+ }
+
+ if (eglInitialize(display->egl.display, &major, &minor) == EGL_FALSE) {
+ fprintf(stderr, "Failed to initialize EGLDisplay\n");
+ goto error;
+ }
+
+ if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
+ fprintf(stderr, "Failed to bind OpenGL ES API\n");
+ goto error;
+ }
+
+ egl_extensions = eglQueryString(display->egl.display, EGL_EXTENSIONS);
+ assert(egl_extensions != NULL);
+
+ if (!check_egl_extension(egl_extensions,
+ "EGL_EXT_image_dma_buf_import")) {
+ fprintf(stderr, "EGL_EXT_image_dma_buf_import not supported\n");
+ goto error;
+ }
+
+ if (!check_egl_extension(egl_extensions,
+ "EGL_KHR_surfaceless_context")) {
+ fprintf(stderr, "EGL_KHR_surfaceless_context not supported\n");
+ goto error;
+ }
+
+ ret = eglChooseConfig(display->egl.display, config_attribs,
+ &display->egl.conf, 1, &count);
+ assert(ret && count >= 1);
+
+ display->egl.context = eglCreateContext(display->egl.display,
+ display->egl.conf,
+ EGL_NO_CONTEXT,
+ context_attribs);
+ if (display->egl.context == EGL_NO_CONTEXT) {
+ fprintf(stderr, "Failed to create EGLContext\n");
+ goto error;
+ }
+#if 0
+ eglMakeCurrent(display->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ display->egl.context);
+
+ if (check_egl_extension(egl_extensions,
+ "EGL_EXT_image_dma_buf_import_modifiers")) {
+ display->egl.has_dma_buf_import_modifiers = true;
+ display->egl.query_dma_buf_modifiers =
+ (void *) eglGetProcAddress("eglQueryDmaBufModifiersEXT");
+ assert(display->egl.query_dma_buf_modifiers);
+ }
+#endif
+ display->egl.create_image =
+ (void *) eglGetProcAddress("eglCreateImageKHR");
+ assert(display->egl.create_image);
+
+ display->egl.destroy_image =
+ (void *) eglGetProcAddress("eglDestroyImageKHR");
+ assert(display->egl.destroy_image);
+
+ display->egl.image_target_texture_2d =
+ (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
+ assert(display->egl.image_target_texture_2d);
+
+ return true;
+
+error:
+ return false;
+}
+
+static struct display *
+create_display()
+{
+ struct display *display = NULL;
+
+ display = (struct display *)calloc(1, sizeof(struct display));
+ if (display == NULL) {
+ fprintf(stderr, "out of memory\n");
+ goto error;
+ }
+
+ display->bufmgr = tbm_bufmgr_init(-1);
+
+ display->display = wl_display_connect(NULL);
+ assert(display->display);
+
+ display->registry = wl_display_get_registry(display->display);
+ wl_registry_add_listener(display->registry,
+ &registry_listener, display);
+ wl_display_roundtrip(display->display);
+
+ if (!display_set_up_egl(display))
+ goto error;
+
+ return display;
+
+error:
+ if (display != NULL)
+ destroy_display(display);
+ return NULL;
+}
+
+static void
+signal_int(int signum)
+{
+ running = 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct sigaction sigint;
+ struct display *display;
+ struct window *window;
+ int opts = 0;
+ char const *drm_render_node = "/dev/dri/renderD128";
+ int ret = 0;
+ int window_size = 256;
+
+
+ display = create_display();
+ if (!display)
+ return 1;
+
+ window = create_window(display, window_size, window_size, opts);
+ if (!window)
+ return 1;
+
+ sigint.sa_handler = signal_int;
+ sigemptyset(&sigint.sa_mask);
+ sigint.sa_flags = SA_RESETHAND;
+ sigaction(SIGINT, &sigint, NULL);
+
+ /* Here we retrieve the linux-dmabuf objects if executed without immed,
+ * or error */
+ wl_display_roundtrip(display->display);
+
+ if (!running)
+ return 1;
+
+ window->initialized = true;
+
+ //if (!window->wait_for_configure)
+ redraw(window, NULL, 0);
+
+ while (running && ret != -1) {
+ ret = wl_display_dispatch_pending(display->display);
+ redraw(window, NULL, 0);
+ }
+
+ fprintf(stderr, "simple-egl-tbm-fbo exiting\n");
+ destroy_window(window);
+ destroy_display(display);
+
+ return 0;
+}