blob: fd39216ebcf6d85fc6fd986aba1d90ed5c4da93a [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
35void notify_surface_create(struct wl_compositor *compositor,
36 struct wl_surface *surface)
37{
38 struct surface_data *sd;
39
40 sd = malloc(sizeof *sd);
41 if (sd == NULL)
42 return;
43
44 sd->handle = 0;
45 wl_surface_set_data(surface, sd);
46
47 glGenTextures(1, &sd->texture);
48}
49
50void notify_surface_destroy(struct wl_compositor *compositor,
51 struct wl_surface *surface)
52{
53 struct egl_compositor *ec = (struct egl_compositor *) compositor;
54 struct surface_data *sd;
55 struct drm_gem_close close_arg;
56 int ret;
57
58 sd = wl_surface_get_data(surface);
59 if (sd == NULL || sd->handle == 0)
60 return;
61
62 close_arg.handle = sd->handle;
63 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
64 if (ret != 0) {
65 fprintf(stderr, "failed to gem_close handle %d: %m\n", sd->handle);
66 }
67
68 glDeleteTextures(1, &sd->texture);
69
70 free(sd);
71}
72
73void notify_surface_attach(struct wl_compositor *compositor,
74 struct wl_surface *surface, uint32_t name,
75 uint32_t width, uint32_t height, uint32_t stride)
76{
77 struct egl_compositor *ec = (struct egl_compositor *) compositor;
78 struct surface_data *sd;
79 struct drm_gem_open open_arg;
80 struct drm_gem_close close_arg;
81 struct drm_i915_gem_pread pread;
82 void *data;
83 uint32_t size;
84 int ret;
85
86 sd = wl_surface_get_data(surface);
87 if (sd == NULL)
88 return;
89
90 if (sd->handle != 0) {
91 close_arg.handle = sd->handle;
92 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
93 if (ret != 0) {
94 fprintf(stderr, "failed to gem_close name %d: %m\n", name);
95 }
96 }
97
98 open_arg.name = name;
99 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg);
100 if (ret != 0) {
101 fprintf(stderr, "failed to gem_open name %d, fd=%d: %m\n", name, ec->gem_fd);
102 return;
103 }
104
105 sd->handle = open_arg.handle;
106 sd->width = width;
107 sd->height = height;
108 sd->stride = stride;
109
110 size = sd->height * sd->stride;
111 data = malloc(size);
112 if (data == NULL) {
113 fprintf(stderr, "swap buffers malloc failed\n");
114 return;
115 }
116
117 pread.handle = sd->handle;
118 pread.pad = 0;
119 pread.offset = 0;
120 pread.size = size;
121 pread.data_ptr = (long) data;
122
123 if (ioctl(ec->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) {
124 fprintf(stderr, "gem pread failed");
125 return;
126 }
127
128 glBindTexture(GL_TEXTURE_2D, sd->texture);
129 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
130 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
131 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
132 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
133 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
134 GL_BGRA, GL_UNSIGNED_BYTE, data);
135
136 free(data);
137}
138
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400139static void
140repaint(struct egl_compositor *ec)
141{
142 struct wl_surface_iterator *iterator;
143 struct wl_surface *surface;
144 struct surface_data *sd;
145 GLint vertices[12];
146 GLint tex_coords[8] = { 1, 0, 1, 1, 0, 1, 0, 0 };
147 GLuint indices[4] = { 0, 1, 2, 3 };
148
149 /* This part is where we actually copy the buffer to screen.
150 * Needs to be part of the repaint loop, not called from the
151 * notify_map handler. */
152
153 glClear(GL_COLOR_BUFFER_BIT);
154
155 iterator = wl_surface_iterator_create(ec->wl_display, 0);
156 while (wl_surface_iterator_next(iterator, &surface)) {
157 sd = wl_surface_get_data(surface);
158 if (sd == NULL)
159 continue;
160
161 vertices[0] = sd->map.x;
162 vertices[1] = sd->map.y;
163 vertices[2] = 0;
164
165 vertices[3] = sd->map.x;
166 vertices[4] = sd->map.y + sd->map.height;
167 vertices[5] = 0;
168
169 vertices[6] = sd->map.x + sd->map.width;
170 vertices[7] = sd->map.y + sd->map.height;
171 vertices[8] = 0;
172
173 vertices[9] = sd->map.x + sd->map.width;
174 vertices[10] = sd->map.y;
175 vertices[11] = 0;
176
177 glBindTexture(GL_TEXTURE_2D, sd->texture);
178 glEnable(GL_TEXTURE_2D);
179 glEnable(GL_BLEND);
180 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
181
182 glEnableClientState(GL_VERTEX_ARRAY);
183 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
184 glVertexPointer(3, GL_INT, 0, vertices);
185 glTexCoordPointer(2, GL_INT, 0, tex_coords);
186 glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, indices);
187 }
188 wl_surface_iterator_destroy(iterator);
189
190 glFlush();
191
192 eglSwapBuffers(ec->display, ec->surface);
193}
194
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400195void notify_surface_map(struct wl_compositor *compositor,
196 struct wl_surface *surface, struct wl_map *map)
197{
198 struct egl_compositor *ec = (struct egl_compositor *) compositor;
199 struct surface_data *sd;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400200
201 sd = wl_surface_get_data(surface);
202 if (sd == NULL)
203 return;
204
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400205 sd->map = *map;
206 repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400207}
208
209struct wl_compositor_interface interface = {
210 notify_surface_create,
211 notify_surface_destroy,
212 notify_surface_attach,
213 notify_surface_map
214};
215
216static const char gem_device[] = "/dev/dri/card0";
217
218struct wl_compositor *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400219wl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400220{
221 EGLConfig configs[64];
222 EGLint major, minor, count;
223 struct egl_compositor *ec;
224 const int width = 800, height = 600;
225
226 ec = malloc(sizeof *ec);
227 if (ec == NULL)
228 return NULL;
229
230 ec->base.interface = &interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400231 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400232
233 ec->display = eglCreateDisplay(gem_device, "i965");
234 if (ec->display == NULL) {
235 fprintf(stderr, "failed to create display\n");
236 return NULL;
237 }
238
239 if (!eglInitialize(ec->display, &major, &minor)) {
240 fprintf(stderr, "failed to initialize display\n");
241 return NULL;
242 }
243
244 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
245 fprintf(stderr, "failed to get configs\n");
246 return NULL;
247 }
248
249 ec->surface = eglCreateSurface(ec->display, configs[24], 0, 0, width, height);
250 if (ec->surface == NULL) {
251 fprintf(stderr, "failed to create surface\n");
252 return NULL;
253 }
254
255 ec->context = eglCreateContext(ec->display, configs[24], NULL, NULL);
256 if (ec->context == NULL) {
257 fprintf(stderr, "failed to create context\n");
258 return NULL;
259 }
260
261 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
262 fprintf(stderr, "failed to make context current\n");
263 return NULL;
264 }
265
266 glViewport(0, 0, width, height);
267 glMatrixMode(GL_PROJECTION);
268 glLoadIdentity();
269 glOrtho(0, width, height, 0, 0, 1000.0);
270 glMatrixMode(GL_MODELVIEW);
271 glClearColor(0.0, 0.1, 0.3, 0.0);
272
273 ec->gem_fd = open(gem_device, O_RDWR);
274 if (ec->gem_fd < 0) {
275 fprintf(stderr, "failed to open drm device\n");
276 return NULL;
277 }
278
279 return &ec->base;
280}