Add README for the adventurous, allow evdev override from getenv().
[profile/ivi/wayland.git] / egl-compositor.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <stdint.h>
5 #include <i915_drm.h>
6 #include <sys/ioctl.h>
7 #include <sys/mman.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <linux/fb.h>
11
12 #include "wayland.h"
13
14 #include <GL/gl.h>
15 #include <eagle.h>
16
17 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
18
19 struct egl_compositor {
20         struct wl_compositor base;
21         EGLDisplay display;
22         EGLSurface surface;
23         EGLContext context;
24         EGLConfig config;
25         struct wl_display *wl_display;
26         int gem_fd;
27 };
28
29 struct surface_data {
30         GLuint texture;
31         struct wl_map map;
32         EGLSurface surface;
33 };
34
35 static void
36 repaint(void *data)
37 {
38         struct egl_compositor *ec = data;
39         struct wl_surface_iterator *iterator;
40         struct wl_surface *surface;
41         struct surface_data *sd;
42         GLint vertices[12];
43         GLint tex_coords[12] = { 0, 0,  0, 1,  1, 0,  1, 1 };
44         GLuint indices[4] = { 0, 1, 2, 3 };
45
46         iterator = wl_surface_iterator_create(ec->wl_display, 0);
47         while (wl_surface_iterator_next(iterator, &surface)) {
48                 sd = wl_surface_get_data(surface);
49                 if (sd == NULL)
50                         continue;
51
52                 vertices[0] = sd->map.x;
53                 vertices[1] = sd->map.y;
54                 vertices[2] = 0;
55
56                 vertices[3] = sd->map.x;
57                 vertices[4] = sd->map.y + sd->map.height;
58                 vertices[5] = 0;
59
60                 vertices[6] = sd->map.x + sd->map.width;
61                 vertices[7] = sd->map.y;
62                 vertices[8] = 0;
63
64                 vertices[9] = sd->map.x + sd->map.width;
65                 vertices[10] = sd->map.y + sd->map.height;
66                 vertices[11] = 0;
67
68                 glBindTexture(GL_TEXTURE_2D, sd->texture);
69                 glEnable(GL_TEXTURE_2D);
70                 glEnable(GL_BLEND);
71                 /* Assume pre-multiplied alpha for now, this probably
72                  * needs to be a wayland visual type of thing. */
73                 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
74
75                 glEnableClientState(GL_VERTEX_ARRAY);
76                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
77                 glVertexPointer(3, GL_INT, 0, vertices);
78                 glTexCoordPointer(2, GL_INT, 0, tex_coords);
79                 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
80         }
81         wl_surface_iterator_destroy(iterator);
82
83         glFlush();
84
85         eglSwapBuffers(ec->display, ec->surface);
86 }
87
88 static void schedule_repaint(struct egl_compositor *ec)
89 {
90         struct wl_event_loop *loop;
91
92         loop = wl_display_get_event_loop(ec->wl_display);
93         wl_event_loop_add_idle(loop, repaint, ec);
94 }
95
96 void notify_surface_create(struct wl_compositor *compositor,
97                            struct wl_surface *surface)
98 {
99         struct surface_data *sd;
100
101         sd = malloc(sizeof *sd);
102         if (sd == NULL)
103                 return;
104
105         sd->surface = EGL_NO_SURFACE;
106         wl_surface_set_data(surface, sd);
107
108         glGenTextures(1, &sd->texture);
109 }
110                                    
111 void notify_surface_destroy(struct wl_compositor *compositor,
112                             struct wl_surface *surface)
113 {
114         struct egl_compositor *ec = (struct egl_compositor *) compositor;
115         struct surface_data *sd;
116
117         sd = wl_surface_get_data(surface);
118         if (sd == NULL)
119                 return;
120
121         if (sd->surface != EGL_NO_SURFACE)
122                 eglDestroySurface(ec->display, sd->surface);
123
124         glDeleteTextures(1, &sd->texture);
125
126         free(sd);
127
128         schedule_repaint(ec);
129 }
130
131 void notify_surface_attach(struct wl_compositor *compositor,
132                            struct wl_surface *surface, uint32_t name, 
133                            uint32_t width, uint32_t height, uint32_t stride)
134 {
135         struct egl_compositor *ec = (struct egl_compositor *) compositor;
136         struct surface_data *sd;
137
138         sd = wl_surface_get_data(surface);
139         if (sd == NULL)
140                 return;
141
142         if (sd->surface != EGL_NO_SURFACE)
143                 eglDestroySurface(ec->display, sd->surface);
144
145         sd->surface = eglCreatePixmapForName(ec->display, ec->config,
146                                              name, width, height, stride, NULL);
147
148         glBindTexture(GL_TEXTURE_2D, sd->texture);
149         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
150         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
151         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
152         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
153         eglBindTexImage(ec->display, sd->surface, GL_TEXTURE_2D);
154
155         schedule_repaint(ec);
156 }
157
158 void notify_surface_map(struct wl_compositor *compositor,
159                         struct wl_surface *surface, struct wl_map *map)
160 {
161         struct egl_compositor *ec = (struct egl_compositor *) compositor;
162         struct surface_data *sd;
163
164         sd = wl_surface_get_data(surface);
165         if (sd == NULL)
166                 return;
167
168         sd->map = *map;
169
170         schedule_repaint(ec);
171 }
172
173 struct wl_compositor_interface interface = {
174         notify_surface_create,
175         notify_surface_destroy,
176         notify_surface_attach,
177         notify_surface_map
178 };
179
180 static const char gem_device[] = "/dev/dri/card0";
181
182 struct wl_compositor *
183 wl_compositor_create(struct wl_display *display)
184 {
185         EGLConfig configs[64];
186         EGLint major, minor, count;
187         struct egl_compositor *ec;
188         const int width = 1024, height = 768;
189
190         ec = malloc(sizeof *ec);
191         if (ec == NULL)
192                 return NULL;
193
194         ec->base.interface = &interface;
195         ec->wl_display = display;
196
197         ec->display = eglCreateDisplayNative(gem_device, "i965");
198         if (ec->display == NULL) {
199                 fprintf(stderr, "failed to create display\n");
200                 return NULL;
201         }
202
203         if (!eglInitialize(ec->display, &major, &minor)) {
204                 fprintf(stderr, "failed to initialize display\n");
205                 return NULL;
206         }
207
208         if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
209                 fprintf(stderr, "failed to get configs\n");
210                 return NULL;
211         }
212
213         ec->config = configs[24];
214         ec->surface = eglCreateSurfaceNative(ec->display, ec->config,
215                                              0, 0, width, height);
216         if (ec->surface == NULL) {
217                 fprintf(stderr, "failed to create surface\n");
218                 return NULL;
219         }
220
221         ec->context = eglCreateContext(ec->display, ec->config, NULL, NULL);
222         if (ec->context == NULL) {
223                 fprintf(stderr, "failed to create context\n");
224                 return NULL;
225         }
226
227         if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
228                 fprintf(stderr, "failed to make context current\n");
229                 return NULL;
230         }
231
232         glViewport(0, 0, width, height);
233         glMatrixMode(GL_PROJECTION);
234         glLoadIdentity();
235         glOrtho(0, width, height, 0, 0, 1000.0);
236         glMatrixMode(GL_MODELVIEW);
237         glClearColor(0.0, 0.05, 0.2, 0.0);
238
239         ec->gem_fd = open(gem_device, O_RDWR);
240         if (ec->gem_fd < 0) {
241                 fprintf(stderr, "failed to open drm device\n");
242                 return NULL;
243         }
244
245         schedule_repaint(ec);
246
247         return &ec->base;
248 }