blob: 049af98ed16f09ab06f72f025490a735b831971c [file] [log] [blame]
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001#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
19struct egl_compositor {
20 struct wl_compositor base;
21 EGLDisplay display;
22 EGLSurface surface;
23 EGLContext context;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040024 struct wl_display *wl_display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040025 int gem_fd;
26};
27
28struct surface_data {
29 uint32_t handle;
30 int32_t width, height, stride;
31 GLuint texture;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040032 struct wl_map map;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040033};
34
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040035static void
36repaint(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];
Kristian Høgsberg5a27f3e2008-11-02 10:55:25 -050043 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040044 GLuint indices[4] = { 0, 1, 2, 3 };
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040045
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;
Kristian Høgsberg48a33ba2008-10-12 12:56:11 -040061 vertices[7] = sd->map.y;
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040062 vertices[8] = 0;
63
64 vertices[9] = sd->map.x + sd->map.width;
Kristian Høgsberg48a33ba2008-10-12 12:56:11 -040065 vertices[10] = sd->map.y + sd->map.height;
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040066 vertices[11] = 0;
67
68 glBindTexture(GL_TEXTURE_2D, sd->texture);
69 glEnable(GL_TEXTURE_2D);
70 glEnable(GL_BLEND);
71 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
72
73 glEnableClientState(GL_VERTEX_ARRAY);
74 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
75 glVertexPointer(3, GL_INT, 0, vertices);
76 glTexCoordPointer(2, GL_INT, 0, tex_coords);
Kristian Høgsberg48a33ba2008-10-12 12:56:11 -040077 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040078 }
79 wl_surface_iterator_destroy(iterator);
80
81 glFlush();
82
83 eglSwapBuffers(ec->display, ec->surface);
84}
85
86static void schedule_repaint(struct egl_compositor *ec)
87{
88 struct wl_event_loop *loop;
89
90 loop = wl_display_get_event_loop(ec->wl_display);
91 wl_event_loop_add_idle(loop, repaint, ec);
92}
93
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040094void notify_surface_create(struct wl_compositor *compositor,
95 struct wl_surface *surface)
96{
97 struct surface_data *sd;
98
99 sd = malloc(sizeof *sd);
100 if (sd == NULL)
101 return;
102
103 sd->handle = 0;
104 wl_surface_set_data(surface, sd);
105
106 glGenTextures(1, &sd->texture);
107}
108
109void notify_surface_destroy(struct wl_compositor *compositor,
110 struct wl_surface *surface)
111{
112 struct egl_compositor *ec = (struct egl_compositor *) compositor;
113 struct surface_data *sd;
114 struct drm_gem_close close_arg;
115 int ret;
116
117 sd = wl_surface_get_data(surface);
118 if (sd == NULL || sd->handle == 0)
119 return;
120
121 close_arg.handle = sd->handle;
122 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
123 if (ret != 0) {
124 fprintf(stderr, "failed to gem_close handle %d: %m\n", sd->handle);
125 }
126
127 glDeleteTextures(1, &sd->texture);
128
129 free(sd);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400130
131 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400132}
133
134void notify_surface_attach(struct wl_compositor *compositor,
135 struct wl_surface *surface, uint32_t name,
136 uint32_t width, uint32_t height, uint32_t stride)
137{
138 struct egl_compositor *ec = (struct egl_compositor *) compositor;
139 struct surface_data *sd;
140 struct drm_gem_open open_arg;
141 struct drm_gem_close close_arg;
142 struct drm_i915_gem_pread pread;
143 void *data;
144 uint32_t size;
145 int ret;
146
147 sd = wl_surface_get_data(surface);
148 if (sd == NULL)
149 return;
150
151 if (sd->handle != 0) {
152 close_arg.handle = sd->handle;
153 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
154 if (ret != 0) {
155 fprintf(stderr, "failed to gem_close name %d: %m\n", name);
156 }
157 }
158
159 open_arg.name = name;
160 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg);
161 if (ret != 0) {
162 fprintf(stderr, "failed to gem_open name %d, fd=%d: %m\n", name, ec->gem_fd);
163 return;
164 }
165
166 sd->handle = open_arg.handle;
167 sd->width = width;
168 sd->height = height;
169 sd->stride = stride;
170
171 size = sd->height * sd->stride;
172 data = malloc(size);
173 if (data == NULL) {
174 fprintf(stderr, "swap buffers malloc failed\n");
175 return;
176 }
177
178 pread.handle = sd->handle;
179 pread.pad = 0;
180 pread.offset = 0;
181 pread.size = size;
182 pread.data_ptr = (long) data;
183
184 if (ioctl(ec->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) {
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400185 fprintf(stderr, "gem pread failed\n");
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400186 return;
187 }
188
189 glBindTexture(GL_TEXTURE_2D, sd->texture);
190 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
191 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
192 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
193 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
194 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
195 GL_BGRA, GL_UNSIGNED_BYTE, data);
196
197 free(data);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400198
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400199 schedule_repaint(ec);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400200}
201
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400202void notify_surface_map(struct wl_compositor *compositor,
203 struct wl_surface *surface, struct wl_map *map)
204{
205 struct egl_compositor *ec = (struct egl_compositor *) compositor;
206 struct surface_data *sd;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400207
208 sd = wl_surface_get_data(surface);
209 if (sd == NULL)
210 return;
211
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400212 sd->map = *map;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400213
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400214 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400215}
216
217struct wl_compositor_interface interface = {
218 notify_surface_create,
219 notify_surface_destroy,
220 notify_surface_attach,
221 notify_surface_map
222};
223
224static const char gem_device[] = "/dev/dri/card0";
225
226struct wl_compositor *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400227wl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400228{
229 EGLConfig configs[64];
230 EGLint major, minor, count;
231 struct egl_compositor *ec;
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400232 const int width = 1024, height = 768;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400233
234 ec = malloc(sizeof *ec);
235 if (ec == NULL)
236 return NULL;
237
238 ec->base.interface = &interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400239 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400240
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400241 ec->display = eglCreateDisplayNative(gem_device, "i965");
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400242 if (ec->display == NULL) {
243 fprintf(stderr, "failed to create display\n");
244 return NULL;
245 }
246
247 if (!eglInitialize(ec->display, &major, &minor)) {
248 fprintf(stderr, "failed to initialize display\n");
249 return NULL;
250 }
251
252 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
253 fprintf(stderr, "failed to get configs\n");
254 return NULL;
255 }
256
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400257 ec->surface = eglCreateSurfaceNative(ec->display, configs[24],
258 0, 0, width, height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400259 if (ec->surface == NULL) {
260 fprintf(stderr, "failed to create surface\n");
261 return NULL;
262 }
263
264 ec->context = eglCreateContext(ec->display, configs[24], NULL, NULL);
265 if (ec->context == NULL) {
266 fprintf(stderr, "failed to create context\n");
267 return NULL;
268 }
269
270 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
271 fprintf(stderr, "failed to make context current\n");
272 return NULL;
273 }
274
275 glViewport(0, 0, width, height);
276 glMatrixMode(GL_PROJECTION);
277 glLoadIdentity();
278 glOrtho(0, width, height, 0, 0, 1000.0);
279 glMatrixMode(GL_MODELVIEW);
Kristian Høgsberga234e702008-10-11 22:13:51 -0400280 glClearColor(0.0, 0.05, 0.2, 0.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400281
282 ec->gem_fd = open(gem_device, O_RDWR);
283 if (ec->gem_fd < 0) {
284 fprintf(stderr, "failed to open drm device\n");
285 return NULL;
286 }
287
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400288 schedule_repaint(ec);
289
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400290 return &ec->base;
291}