diff options
author | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2011-02-01 02:18:57 +0100 |
---|---|---|
committer | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2011-02-01 02:18:57 +0100 |
commit | f7ce9622253ce7f4721fb2f51cabeb123101f3a6 (patch) | |
tree | 26ec7584ab04e808ea425e483dd2751bec29cf24 |
Add egl-wayland-{image,surface}
-rw-r--r-- | egl-wayland-image.c | 399 | ||||
-rw-r--r-- | egl-wayland-surface.c | 265 |
2 files changed, 664 insertions, 0 deletions
diff --git a/egl-wayland-image.c b/egl-wayland-image.c new file mode 100644 index 0000000..56a8739 --- /dev/null +++ b/egl-wayland-image.c @@ -0,0 +1,399 @@ +/* + * Copyright © 2011 Benjamin Franzke + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <math.h> +#include <assert.h> + +#include <wayland-client.h> +#include <wayland-egl.h> + +#define GL_GLEXT_PROTOTYPES +#define EGL_EGLEXT_PROTOTYPES +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> + +struct display { + struct wl_display *display; + struct wl_egl_display *egl_display; + struct wl_compositor *compositor; + struct wl_shell *shell; + struct { + EGLDisplay dpy; + EGLContext ctx; + } egl; + uint32_t mask; +}; + +struct window { + struct display *display; + struct { + int width, height; + } geometry; + struct { + GLuint fbo; + GLuint color_rbo; + + GLuint program; + GLuint rotation_uniform; + + GLuint pos; + GLuint col; + } gl; + struct { + struct wl_surface *surface; + struct wl_egl_image *egl_image; + } surface; + int dx, dy; + int attached_width, attached_height; +}; + +static const char *vert_shader_text = + "uniform mat4 rotation;\n" + "attribute vec4 pos;\n" + "attribute vec4 color;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_Position = rotation * pos;\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 void +init_egl(struct display *display) +{ + static const EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + EGLint major, minor; + EGLBoolean ret; + + display->egl.dpy = + eglGetDisplay((EGLNativeDisplayType) display->egl_display); + assert(display->egl.dpy); + + ret = eglInitialize(display->egl.dpy, &major, &minor); + assert(ret == EGL_TRUE); + ret = eglBindAPI(EGL_OPENGL_ES_API); + assert(ret == EGL_TRUE); + + display->egl.ctx = eglCreateContext(display->egl.dpy, NULL, + EGL_NO_CONTEXT, context_attribs); + assert(display->egl.ctx); + ret = eglMakeCurrent(display->egl.dpy, NULL, NULL, display->egl.ctx); + assert(ret == EGL_TRUE); +} + +static GLuint +create_shader(struct window *window, 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); + exit(1); + } + + return shader; +} + +static void +init_gl(struct window *window) +{ + GLuint frag, vert; + GLint status; + + glGenFramebuffers(1, &window->gl.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, window->gl.fbo); + + glGenRenderbuffers(1, &window->gl.color_rbo); + + glViewport(0, 0, window->geometry.width, window->geometry.height); + + frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER); + vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER); + + window->gl.program = glCreateProgram(); + glAttachShader(window->gl.program, frag); + glAttachShader(window->gl.program, vert); + glLinkProgram(window->gl.program); + + glGetProgramiv(window->gl.program, GL_LINK_STATUS, &status); + if (!status) { + char log[1000]; + GLsizei len; + glGetProgramInfoLog(window->gl.program, 1000, &len, log); + fprintf(stderr, "Error: linking:\n%*s\n", len, log); + exit(1); + } + + glUseProgram(window->gl.program); + + window->gl.pos = 0; + window->gl.pos = 1; + + glBindAttribLocation(window->gl.program, window->gl.pos, "pos"); + glBindAttribLocation(window->gl.program, window->gl.col, "color"); + glLinkProgram(window->gl.program); + + window->gl.rotation_uniform = + glGetUniformLocation(window->gl.program, "rotation"); +} + +static void +create_surface(struct window *window) +{ + struct display *display = window->display; + struct wl_visual *visual; + + window->surface.surface = + wl_compositor_create_surface(display->compositor); + wl_surface_set_user_data(window->surface.surface, window); + + visual = wl_display_get_premultiplied_argb_visual(display->display); + window->surface.egl_image = wl_egl_create_image(display->egl.dpy, + window->geometry.width, + window->geometry.height, + visual, 0); + + wl_surface_map_toplevel(window->surface.surface); + + glBindRenderbuffer(GL_RENDERBUFFER, window->gl.color_rbo); + glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, + wl_egl_image_get_image(window->surface.egl_image)); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, window->gl.color_rbo); + + assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == + GL_FRAMEBUFFER_COMPLETE); +} + +static void +redraw(void *data, uint32_t time) +{ + struct window *window = data; + static const GLfloat verts[3][2] = { + { -0.5, -0.5 }, + { 0.5, -0.5 }, + { 0, 0.5 } + }; + static const GLfloat colors[3][3] = { + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 } + }; + GLfloat angle; + GLfloat rotation[4][4] = { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }; + static const int32_t speed_div = 5; + static uint32_t start_time = 0; + + if (start_time == 0) + start_time = time; + + angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0; + rotation[0][0] = cos(angle); + rotation[0][2] = sin(angle); + rotation[2][0] = -sin(angle); + rotation[2][2] = cos(angle); + + glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE, + (GLfloat *) rotation); + + glClearColor(0.0, 0.0, 0.0, 0.5); + glClear(GL_COLOR_BUFFER_BIT); + + glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts); + glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors); + glEnableVertexAttribArray(window->gl.pos); + glEnableVertexAttribArray(window->gl.col); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisableVertexAttribArray(window->gl.pos); + glDisableVertexAttribArray(window->gl.col); + + wl_egl_image_attach(window->display->egl_display, + window->surface.egl_image, + window->surface.surface, + window->dx, window->dy); + window->attached_width = window->geometry.width; + window->attached_height = window->geometry.width; + + window->dx = window->dy = 0; + + wl_surface_damage(window->surface.surface, 0, 0, + window->geometry.width, window->geometry.height); + + wl_display_frame_callback(window->display->display, redraw, window); +} + +static void +handle_configure(void *data, struct wl_shell *shell, + uint32_t time, uint32_t edges, + struct wl_surface *surface, + int32_t width, int32_t height) +{ + struct display *d = data; + struct window *window = wl_surface_get_user_data(surface); + int dx = 0; + int dy = 0; + struct wl_visual *visual; + + struct wl_egl_image *old_egl_image = window->surface.egl_image; + +#if 1 + printf("event: width: %d height: %d\natm: width: %d height: %d\n", + width, height, window->attached_width, window->attached_height); + + dx = window->attached_width - width; + dy = window->attached_height - height; + + window->dx = -dx; + window->dy = dy; + window->geometry.width = width ; + window->geometry.height = height; + + printf("calculated: width: %d, height: %d\n", + window->geometry.width, window->geometry.height); + printf("\n"); +#else + window->dx = 0; + window->dx = 0; + window->geometry.width = width; + window->geometry.height = height; +#endif + + visual = wl_display_get_premultiplied_argb_visual(d->display); + window->surface.egl_image = + wl_egl_create_image(d->egl.dpy, + window->geometry.width, + window->geometry.height, + visual, 0); + + assert(window->surface.egl_image); + + glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, + wl_egl_image_get_image(window->surface.egl_image)); + + wl_egl_destroy_image(old_egl_image); + + glViewport(0, 0, window->geometry.width, window->geometry.height); +} + +static const struct wl_shell_listener shell_listener = { + handle_configure, +}; + +static void +display_handle_global(struct wl_display *display, uint32_t id, + const char *interface, uint32_t version, void *data) +{ + struct display *d = data; + + if (strcmp(interface, "compositor") == 0) { + d->compositor = wl_compositor_create(display, id); + } else if (strcmp(interface, "shell") == 0) { + d->shell = wl_shell_create(display, id); + wl_shell_add_listener(d->shell, &shell_listener, d); + } +} + +static int +event_mask_update(uint32_t mask, void *data) +{ + struct display *d = data; + + d->mask = mask; + + return 0; +} + +int +main(int argc, char **argv) +{ + struct display display = { 0 }; + struct window window = { 0 }; + + memset(&display, 0, sizeof display); + memset(&window, 0, sizeof window); + + window.display = &display; + window.geometry.width = 250; + window.geometry.height = 250; + + display.display = wl_display_connect(NULL); + assert(display.display); + + display.egl_display = wl_egl_create_native_display(display.display); + assert(display.egl_display); + + wl_display_add_global_listener(display.display, + display_handle_global, &display); + /* process connection events */ + wl_display_iterate(display.display, WL_DISPLAY_READABLE); + + init_egl(&display); + init_gl(&window); + create_surface(&window); + + wl_display_frame_callback(display.display, redraw, &window); + wl_display_get_fd(display.display, event_mask_update, &display); + + while (true) + wl_display_iterate(display.display, display.mask); + + return 0; +} diff --git a/egl-wayland-surface.c b/egl-wayland-surface.c new file mode 100644 index 0000000..8ea2002 --- /dev/null +++ b/egl-wayland-surface.c @@ -0,0 +1,265 @@ +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <assert.h> + +#include <GL/gl.h> +#include <EGL/egl.h> + +#include <wayland-client.h> +#include <wayland-egl.h> + +struct display { + struct wl_display *display; + struct wl_egl_display *egl_display; + struct { + struct wl_compositor *compositor; + struct wl_shell *shell; + } interface; + + struct { + EGLDisplay dpy; + EGLConfig conf; + EGLContext ctx; + } egl; + + uint32_t mask; +}; + +struct window { + struct display *display; + struct wl_surface *surface; + struct wl_egl_surface *egl_surface; + + int width, height; + + struct { + EGLSurface surf; + } egl; +}; + +static void +init_egl(struct display *display) +{ + EGLint major, minor; + EGLint num_config; + EGLint config_attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 1, + EGL_GREEN_SIZE, 1, + EGL_BLUE_SIZE, 1, + //EGL_DEPTH_SIZE, 1, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE + }; + + display->egl.dpy = eglGetDisplay((EGLNativeDisplayType) display->egl_display); + assert(display->egl.dpy); + + assert(eglInitialize(display->egl.dpy, &major, &minor)); + + assert(eglBindAPI(EGL_OPENGL_API)); + assert(eglChooseConfig(display->egl.dpy, config_attribs, + &display->egl.conf, 1, &num_config)); + assert(num_config == 1); + + display->egl.ctx = eglCreateContext(display->egl.dpy, display->egl.conf, + EGL_NO_CONTEXT, NULL); + assert(display->egl.ctx); +} + +static void +create_egl_surface(struct display *display, struct window *window) +{ + + window->egl_surface = wl_egl_create_native_surface(window->surface, + window->width, + window->height); + + printf("surface: %p\n", window->surface); + window->egl.surf = + eglCreateWindowSurface(display->egl.dpy, display->egl.conf, + (EGLNativeWindowType) window->egl_surface, + NULL); + assert(window->egl.surf); + assert(eglMakeCurrent(display->egl.dpy, + window->egl.surf, window->egl.surf, + display->egl.ctx)); +} + +static void +init_gl(struct window *window) +{ + GLfloat ar; + + glViewport(0, 0, window->width, window->height); + ar = (GLfloat)window->width / (GLfloat)window->height; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-ar, ar, -1, 1, 5.0, 60.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -10.0); +} + +static void +redraw(void *data, uint32_t time) +{ + struct window *window = data; + static const GLfloat verts[3][2] = { + { -1, -1 }, + { 1, -1 }, + { 0, 1 } + }; + static const GLfloat colors[3][3] = { + { 1, 0, 1 }, + { 0, 1, 0 }, + { 0, 0, 1 } + }; + static GLfloat speed = 0.2; + static uint32_t start_time = 0; + + if (start_time == 0) + start_time = time; + + glClearColor(0.0, 0.0, 0.0, 0.5); + glClear(GL_COLOR_BUFFER_BIT); + + glPushMatrix(); + glRotatef(speed * (time-start_time), 0, 1, 0); + + glVertexPointer(2, GL_FLOAT, 0, verts); + glColorPointer(3, GL_FLOAT, 0, colors); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + glPopMatrix(); + + eglSwapBuffers(window->display->egl.dpy, window->egl.surf); + + wl_display_frame_callback(window->display->display, redraw, window); +} + +enum window_location { + WINDOW_INTERIOR = 0, + WINDOW_RESIZING_TOP = 1, + WINDOW_RESIZING_BOTTOM = 2, + WINDOW_RESIZING_LEFT = 4, + WINDOW_RESIZING_TOP_LEFT = 5, + WINDOW_RESIZING_BOTTOM_LEFT = 6, + WINDOW_RESIZING_RIGHT = 8, + WINDOW_RESIZING_TOP_RIGHT = 9, + WINDOW_RESIZING_BOTTOM_RIGHT = 10, + WINDOW_RESIZING_MASK = 15, + WINDOW_EXTERIOR = 16, + WINDOW_TITLEBAR = 17, + WINDOW_CLIENT_AREA = 18, +}; +static void +handle_configure(void *data, struct wl_shell *shell, + uint32_t time, uint32_t edges, + struct wl_surface *surface, + int32_t width, int32_t height) +{ + struct display *d = data; + struct window *window = wl_surface_get_user_data(surface); + int dx = 0; + int dy = 0; + + int t_width, t_height; + + eglQuerySurface(d->egl.dpy, window->egl.surf, EGL_WIDTH, &t_width); + eglQuerySurface(d->egl.dpy, window->egl.surf, EGL_HEIGHT, &t_height); + + edges = 5; + if (edges & WINDOW_RESIZING_LEFT) + dx = t_width - width; + + if (edges & WINDOW_RESIZING_TOP) + dy = t_height - height; + + t_width = width + 2*dx; + t_height = height + 2*dy; + + wl_egl_surface_resize(window->egl_surface, t_width, t_height, -dx, -dy); + + window->width = t_width; + window->height = t_height; + + glViewport(0, 0, window->width, window->height); +} + +static const struct wl_shell_listener wayland_shell_listener = { + handle_configure, +}; + +static void +display_handle_global(struct wl_display *display, uint32_t id, + const char *interface, uint32_t version, void *data) +{ + struct display *d = data; + + if (strcmp(interface, "compositor") == 0) { + d->interface.compositor = wl_compositor_create(display, id); + } else if (strcmp(interface, "shell") == 0) { + d->interface.shell = wl_shell_create(display, id); + wl_shell_add_listener(d->interface.shell, &wayland_shell_listener, d); + } +} + +static int +event_mask_update(uint32_t mask, void *data) +{ + struct display *d = data; + + d->mask = mask; + + return 0; +} + +int +main(int argc, char **argv) +{ + struct display display = { 0 }; + struct window window = { 0 }; + + window.display = &display; + window.width = 250; + window.height = 250; + + display.display = wl_display_connect(NULL); + assert(display.display); + + display.egl_display = wl_egl_create_native_display(display.display); + assert(display.egl_display); + + wl_display_add_global_listener(display.display, + display_handle_global, &display); + /* process connection events */ + wl_display_iterate(display.display, WL_DISPLAY_READABLE); + + init_egl(&display); + window.surface = + wl_compositor_create_surface(display.interface.compositor); + wl_surface_set_user_data(window.surface, &window); + create_egl_surface(&display, &window); + + init_gl(&window); + + wl_surface_map_toplevel(window.surface); + + wl_display_frame_callback(display.display, redraw, &window); + + wl_display_get_fd(display.display, event_mask_update, &display); + while (true) + wl_display_iterate(display.display, display.mask); + + return 0; +} |